wake-up-neo.com

Benutzerdefinierte Methodennamen in der ASP.NET-Web-API

Ich konvertiere von der WCF-Web-API zur neuen ASP.NET MVC 4-Web-API. Ich habe einen UsersController und möchte eine Methode namens Authenticate haben. Ich sehe Beispiele für die Vorgehensweise bei GetAll, GetOne, Post und Delete. Was ist jedoch, wenn ich diesen Diensten zusätzliche Methoden hinzufügen möchte? Zum Beispiel sollte mein UsersService eine Methode namens Authenticate haben, bei der ein Benutzername und ein Kennwort übergeben werden. Dies funktioniert jedoch nicht.

public class UsersController : BaseApiController
{
    public string GetAll()
    {
        return "getall!";
    }

    public string Get(int id)
    {
        return "get 1! " + id;
    }

    public User GetAuthenticate(string userName, string password, string applicationName)
    {
        LogWriter.Write(String.Format("Received authenticate request for username {0} and password {1} and application {2}",
            userName, password, applicationName));

        //check if valid leapfrog login.
        var decodedUsername = userName.Replace("%40", "@");
        var encodedPassword = password.Length > 0 ? Utility.HashString(password) : String.Empty;
        var leapFrogUsers = LeapFrogUserData.FindAll(decodedUsername, encodedPassword);

        if (leapFrogUsers.Count > 0)
        {
            return new User
            {
                Id = (uint)leapFrogUsers[0].Id,
                Guid = leapFrogUsers[0].Guid
            };
        }
        else
            throw new HttpResponseException("Invalid login credentials");
    }
}

Ich kann zu myapi/api/users/navigieren und es wird GetAll aufgerufen. Ich kann zu myapi/api/users/1 navigieren und es wird Get aufgerufen. Wenn ich jedoch myapi/api/users/authenticate? Username = {0} aufrufe, wird Get aufgerufen. & password = {1} ruft dann Get (NOT Authenticate) auf und es tritt ein Fehler auf:

Das Parameterwörterbuch enthält einen Null-Eintrag für den Parameter 'id' des nicht nullwertfähigen Typs 'System.Int32' für die Methode 'System.String Get (Int32)' in 'Navtrak.Services.WCF.NavtrakAPI.Controllers.UsersController'. Ein optionaler Parameter muss ein Referenztyp oder ein nullwertfähiger Typ sein oder als optionaler Parameter deklariert werden.

Wie kann ich benutzerdefinierte Methodennamen wie Authenticate aufrufen?

107
Justin

Standardmäßig folgt die Routenkonfiguration den RESTFul-Konventionen, was bedeutet, dass nur die Aktionsnamen Get, Post, Put und Delete akzeptiert werden (siehe Route in global.asax => Standardmäßig können Sie keinen Aktionsnamen angeben => es verwendet das HTTP-Verb zum Versenden). Wenn Sie also eine GET-Anforderung an /api/users/authenticate Senden, rufen Sie im Grunde die Aktion Get(int id) auf und übergeben id=authenticate, Die offensichtlich abstürzt, weil Ihre Get-Aktion eine Ganzzahl erwartet.

Wenn Sie andere Aktionsnamen als die Standardnamen haben möchten, können Sie Ihre Routendefinition in global.asax Ändern:

Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { action = "get", id = RouteParameter.Optional }
);

Nun können Sie zu /api/values/getauthenticate Navigieren, um den Benutzer zu authentifizieren.

127
Darin Dimitrov

Dies ist die beste Methode, die ich bisher entwickelt habe, um zusätzliche GET-Methoden zu integrieren und gleichzeitig die normalen REST -Methoden zu unterstützen. Fügen Sie Ihrem WebApiConfig die folgenden Routen hinzu:

routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"\d+" });
routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}");
routes.MapHttpRoute("DefaultApiGet", "Api/{controller}", new { action = "Get" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
routes.MapHttpRoute("DefaultApiPost", "Api/{controller}", new {action = "Post"}, new {httpMethod = new HttpMethodConstraint(HttpMethod.Post)});

Ich habe diese Lösung mit der folgenden Testklasse verifiziert. Ich konnte erfolgreich jede Methode in meinem Controller unten treffen:

public class TestController : ApiController
{
    public string Get()
    {
        return string.Empty;
    }

    public string Get(int id)
    {
        return string.Empty;
    }

    public string GetAll()
    {
        return string.Empty;
    }

    public void Post([FromBody]string value)
    {
    }

    public void Put(int id, [FromBody]string value)
    {
    }

    public void Delete(int id)
    {
    }
}

Ich habe überprüft, dass die folgenden Anforderungen unterstützt werden:

GET /Test
GET /Test/1
GET /Test/GetAll
POST /Test
PUT /Test/1
DELETE /Test/1

Anmerkung Wenn Ihre zusätzlichen GET-Aktionen nicht mit 'Get' beginnen, können Sie der Methode ein HttpGet-Attribut hinzufügen.

86
sky-dev

Ich bin Tage in der MVC4-Welt.

Ich besitze einen SitesAPIController und benötigte eine benutzerdefinierte Methode, die wie folgt aufgerufen werden kann:

http://localhost:9000/api/SitesAPI/Disposition/0

Mit unterschiedlichen Werten für den letzten Parameter, der mit unterschiedlichen Dispositionen aufgezeichnet werden soll.

Was schließlich für mich gearbeitet hat, war:

Die Methode im SitesAPIController:

// GET api/SitesAPI/Disposition/1
[ActionName("Disposition")]
[HttpGet]
public Site Disposition(int disposition)
{
    Site site = db.Sites.Where(s => s.Disposition == disposition).First();
    return site;
}

Und das in der WebApiConfig.cs

// this was already there
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

// this i added
config.Routes.MapHttpRoute(
    name: "Action",
    routeTemplate: "api/{controller}/{action}/{disposition}"
 );

Solange ich {disposition} {id} nannte, begegnete ich:

{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:9000/api/SitesAPI/Disposition/0'.",
"MessageDetail": "No action was found on the controller 'SitesAPI' that matches the request."
}

Als ich es in {disposition} umbenannte, fing es an zu funktionieren. Anscheinend stimmt der Parametername also mit dem Wert im Platzhalter überein.

Fühlen Sie sich frei, diese Antwort zu bearbeiten, um sie genauer/erklärender zu machen.

19
Kinjal Dixit

Web-API erwartet standardmäßig eine URL in Form von API/{Controller}/{ID}, um dieses Standard-Routing zu überschreiben. Sie können das Routing auf zwei Arten einstellen.

Erste Option:

Fügen Sie unten die Routenregistrierung in WebApiConfig.cs hinzu

config.Routes.MapHttpRoute(
    name: "CustomApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

Dekorieren Sie Ihre Aktionsmethode mit HttpGet und den folgenden Parametern

[HttpGet]
public HttpResponseMessage ReadMyData(string param1,
                        string param2, string param3)

 {

// your code here

}

für den Aufruf der obigen Methode wird die URL wie folgt lauten

http: // localhost: [yourport]/api/MyData/ReadMyData? param1 = value1 & param2 = value2 & param3 = value

Zweite Option Fügen Sie der Controller-Klasse ein Routenpräfix hinzu und dekorieren Sie Ihre Aktionsmethode mit HttpGet (siehe unten). In diesem Fall müssen keine WebApiConfig.cs geändert werden. Es kann Standardrouting haben.

[RoutePrefix("api/{controller}/{action}")]
public class MyDataController : ApiController
{

[HttpGet]
public HttpResponseMessage ReadMyData(string param1,
                        string param2, string param3)

{

// your code here

}

}

für den Aufruf der obigen Methode wird die URL wie folgt lauten

http: // localhost: [yourport]/api/MyData/ReadMyData? param1 = value1 & param2 = value2 & param3 = value

14

Falls Sie ASP.NET 5 mit ASP.NET MVC 6 verwenden -), die meisten dieser Antworten funktionieren einfach nicht, weil Sie MVC normalerweise die entsprechende Routensammlung für Sie erstellen lassen (unter Verwendung der Standard-RESTful-Konventionen), was bedeutet, dass Sie keinen Routes.MapRoute() -Aufruf finden nach Belieben zu bearbeiten.

Die ConfigureServices() -Methode, die von der Datei Startup.cs Aufgerufen wird, registriert MVC mit dem in ASP.NET 5 integrierten Abhängigkeitsinjektionsframework: auf diese Weise, wenn Sie später ApplicationBuilder.UseMvc() aufrufen Klasse fügt das MVC-Framework diese Standardrouten automatisch Ihrer App hinzu. Wir können einen Blick hinter die Kulissen werfen, indem wir uns die Implementierung der UseMvc() -Methode im Quellcode des Frameworks ansehen:

public static IApplicationBuilder UseMvc(
    [NotNull] this IApplicationBuilder app,
    [NotNull] Action<IRouteBuilder> configureRoutes)
{
    // Verify if AddMvc was done before calling UseMvc
    // We use the MvcMarkerService to make sure if all the services were added.
    MvcServicesHelper.ThrowIfMvcNotRegistered(app.ApplicationServices);

    var routes = new RouteBuilder
    {
        DefaultHandler = new MvcRouteHandler(),
        ServiceProvider = app.ApplicationServices
    };

    configureRoutes(routes);

    // Adding the attribute route comes after running the user-code because
    // we want to respect any changes to the DefaultHandler.
    routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(
        routes.DefaultHandler,
        app.ApplicationServices));

    return app.UseRouter(routes.Build());
}

Das Gute daran ist, dass das Framework jetzt die ganze harte Arbeit erledigt, alle Aktionen des Controllers durchläuft und deren Standardrouten einrichtet, wodurch Sie redundante Arbeit sparen.

Das Schlimme ist, dass es kaum oder gar keine Dokumentation gibt, wie Sie Ihre eigenen Routen hinzufügen können. Glücklicherweise können Sie dies leicht tun, indem Sie entweder ein Konventionsbasiertes und/oder ein Attributbasiertes Ansatz (aka Attribute Routing).

Konventionsbasiert

Ersetzen Sie dies in Ihrer Startup.cs-Klasse:

app.UseMvc();

mit diesem:

app.UseMvc(routes =>
            {
                // Route Sample A
                routes.MapRoute(
                    name: "RouteSampleA",
                    template: "MyOwnGet",
                    defaults: new { controller = "Items", action = "Get" }
                );
                // Route Sample B
                routes.MapRoute(
                    name: "RouteSampleB",
                    template: "MyOwnPost",
                    defaults: new { controller = "Items", action = "Post" }
                );
            });

Attributbasiert

Das Tolle an MVC6 ist, dass Sie Routen auch pro Controller definieren können, indem Sie entweder die Controller -Klasse und/oder die Action -Methoden mit den entsprechenden RouteAttribute und dekorieren/oder HttpGet/HttpPost Vorlagenparameter, wie zum Beispiel die folgenden:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;

namespace MyNamespace.Controllers
{
    [Route("api/[controller]")]
    public class ItemsController : Controller
    {
        // GET: api/items
        [HttpGet()]
        public IEnumerable<string> Get()
        {
            return GetLatestItems();
        }

        // GET: api/items/5
        [HttpGet("{num}")]
        public IEnumerable<string> Get(int num)
        {
            return GetLatestItems(5);
        }       

        // GET: api/items/GetLatestItems
        [HttpGet("GetLatestItems")]
        public IEnumerable<string> GetLatestItems()
        {
            return GetLatestItems(5);
        }

        // GET api/items/GetLatestItems/5
        [HttpGet("GetLatestItems/{num}")]
        public IEnumerable<string> GetLatestItems(int num)
        {
            return new string[] { "test", "test2" };
        }

        // POST: /api/items/PostSomething
        [HttpPost("PostSomething")]
        public IActionResult Post([FromBody]string someData)
        {
            return Content("OK, got it!");
        }
    }
}

Dieser Controller verarbeitet die folgenden Anforderungen:

 [GET] api/items
 [GET] api/items/5
 [GET] api/items/GetLatestItems
 [GET] api/items/GetLatestItems/5
 [POST] api/items/PostSomething

Beachten Sie auch, dass bei Verwendung der beiden Methoden auf Attributen basierende Routen (sofern definiert) die auf Konventionen basierenden Routen und auf beiden die mit UseMvc() definierten Standardrouten überschreiben würden.

Für weitere Informationen können Sie auch lesen Sie den folgenden Beitrag auf meinem Blog.

10
Darkseal

Weitere Informationen zu benannten Aktionen finden Sie in diesem Artikel. Es zeigt auch, dass Sie das Attribut [HttpGet] verwenden können, anstatt dem Aktionsnamen "get" voran zu stellen.

http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

9
Andrew