ASP.NET Web API'de özel yöntem adları


110

WCF Web API'sinden yeni ASP.NET MVC 4 Web API'sine dönüştürme yapıyorum. Bir UsersController'ım var ve Authenticate adlı bir yönteme sahip olmak istiyorum. GetAll, GetOne, Post ve Delete işlemlerinin nasıl yapılacağına dair örnekler görüyorum, ancak bu hizmetlere fazladan yöntemler eklemek istersem ne olur? Örneğin, My UsersService, bir kullanıcı adı ve parolayı geçtikleri yerde Authenticate adında bir yönteme sahip olmalı, ancak bu çalışmıyor.

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");
    }
}

Myapi / api / users / adresine göz atabilirim ve GetAll'ı arayacak ve myapi / api / users / 1'e göz atabilirim ve Get'i arayacak, ancak myapi / api / users / Authenticate? Username = {0} & password = {1}, ardından Get (Kimlik Doğrulaması DEĞİL) öğesini çağıracak ve hata verecektir:

Parametreler sözlüğü, 'Navtrak.Services.WCF.NavtrakAPI.Controllers.UsersController' içindeki 'System.String Get (Int32)' yöntemi için null yapılamayan 'System.Int32' türündeki 'id' parametresi için boş bir girdi içerir. İsteğe bağlı bir parametre bir başvuru türü, null atanabilir bir tür olmalı veya isteğe bağlı bir parametre olarak bildirilmelidir.

Kimlik Doğrulama gibi özel yöntem adlarını nasıl çağırabilirim?


Lütfen şu bağlantıya bakın: 5. cevap stackoverflow.com/questions/12775590/…
Vishwa G

Yanıtlar:


137

Varsayılan olarak, rota yapılandırması RESTFul kurallarını izler, yani yalnızca Al, Gönder, Koy ve Sil eylem adlarını kabul eder (rotaya bakın global.asax => varsayılan olarak herhangi bir eylem adı belirtmenize izin vermez => göndermek için HTTP fiilini kullanır). Dolayısıyla, size bir GET isteği gönderdiğinizde /api/users/authenticate, temelde Get(int id)eylemi çağırırsınız ve geçme işlemi id=authenticateaçıkça çöker, çünkü Get eyleminiz bir tam sayı beklemektedir.

Standart olanlardan farklı eylem adlarına sahip olmak istiyorsanız, rota tanımınızı şurada değiştirebilirsiniz global.asax:

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

Artık /api/values/getauthenticatekullanıcının kimliğini doğrulamak için adresine gidebilirsiniz .


20
Diğer işlemlere izin verirken Get (id), Get () Koy, Sil, Gönder'i kullanmaya devam etmenin bir yolu var mı?
Shawn Mclean

@ShawnMclean Sanırım {action}üzerinde kısıtlama olmadan başka bir yol belirtebilirsiniz , {id}böylece intveya dışındaki herhangi bir şey Guid(veya her neyse) eşleşmez. O zaman Darin
Steve Greatrex'in

2
Burada daha önemli bir nokta, bu yönlendirme stiliyle, izin verilen HTTP yöntemlerini ([HttpGet] gibi) belirtmek için öznitelikleri kullanmanız gerektiğidir.
Himalaya Garg

1
başka eylemler kullanmanız gerektiğine emin misiniz? REST sözleşmelerine gerçekten uymaya çalıştınız mı? Başka eylemler kullanmak gerekli olmamalıdır.
niico

1
@niico: Get () 'in döndüreceği öğelerin sayısını döndüren bir Count () yöntemine sahip olmak istediğinizi düşünün. Bunu Get (), Get (id), Post (...), Put (...) veya Delete (id) içine nasıl sığdıracağımı bilmiyorum. Ve tabii ki hayal edebileceğim, belirsiz bir şekilde daha olası yöntemler var.
Jens Mander

88

Bu, normal REST yöntemlerini de desteklerken ekstra GET yöntemlerini dahil etmek için şimdiye kadar bulduğum en iyi yöntemdir. WebApiConfig konsolunuza aşağıdaki yolları ekleyin:

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)});

Bu çözümü aşağıdaki test sınıfıyla doğruladım. Aşağıdaki denetleyicimdeki her yöntemi başarıyla vurabildim:

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)
    {
    }
}

Aşağıdaki istekleri desteklediğini doğruladım:

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

Not ekstra GET eylemleri ile başlayan yoksa yöntemine HttpGet öznitelik eklemek isteyebilir 'Get That'.


1
güzel çözüm Ben yapılandırmak varsa, bana söyler misiniz putve deleteüzerinde olduğu gibi fiiller bu tür getve postçok iyi çalışır?
Felipe Oriani

1
Kanımca bu, WebAPI projeleri için varsayılanlara dahil edilmelidir (belki de yorumlanmıştır). Size aynı anda WebAPI VE MVC tarzı rotalar verir ...
John Culviner

1
@FelipeOriani, bu işlemi uygulamak istediğiniz kaynağı tanımlamak için tipik olarak bir id parametresine eşlik edeceğinden, bu istekler putveya deletefiilleri yapılandırmak isteyeceğinizi veya buna ihtiyaç duyacağınızı sanmıyorum . Bir deleteçağrının /api/foohata vermesi gerekir çünkü hangi foo'yu silmeye çalışıyorsunuz? Bu nedenle, DefaultApiWithId yolu bu durumları iyi işlemelidir.
nwayve

4
bu benim için hiç işe yaramadı. temel bir GET yapmaya çalıştığımda hata mesajları aldım.
Matt

İlki olan DefaultApiWithId için varsayılanlar yeni {id = RouteParameter.Optional} yerine boş olmamalı mı? 'İd' gerekli değil mi?
Johnny Oshika

22

MVC4 dünyasına günler giriyorum.

Değeri ne olursa olsun, bir SitesAPIController'ım var ve şöyle adlandırılabilecek özel bir yönteme ihtiyacım vardı:

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

Son parametre için farklı değerler ile farklı düzenlemeler ile kayıt almak.

Sonunda benim için işe yarayan şey şuydu:

SitesAPIController'daki yöntem:

// 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;
}

Ve bu WebApiConfig.cs içinde

// 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}"
 );

Karşılaştığım {disposition} 'u {id} olarak adlandırdığım sürece:

{
"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."
}

Onu {disposition} olarak yeniden adlandırdığımda çalışmaya başladı. Görünüşe göre parametre adı yer tutucudaki değer ile eşleşiyor.

Daha doğru / açıklayıcı hale getirmek için bu yanıtı düzenlemekten çekinmeyin.


Bahşiş için teşekkürler. Ben de seninle aynı hatayı yapıyordum.
abhi

16

Varsayılan olarak Web Api, api / {controller} / {id} biçimindeki URL'nin bu varsayılan yönlendirmeyi geçersiz kılmasını bekler. Yönlendirmeyi aşağıdaki iki yoldan biriyle ayarlayabilirsiniz.

İlk seçenek:

WebApiConfig.cs'de aşağıdaki yol kaydını ekleyin

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

Eylem yönteminizi HttpGet ve aşağıdaki gibi parametrelerle dekore edin

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

 {

// your code here

}

yukarıdaki yöntemi çağırmak için url aşağıdaki gibi olacaktır

http: // localhost: [portNo] / API / MyData / ReadMyData Param1 = deger1 & param2 = deger2 & param3 = deger3

İkinci seçenek Controller sınıfına yol öneki ekleyin ve aşağıdaki gibi eylem yönteminizi HttpGet ile dekore edin. Bu durumda herhangi bir WebApiConfig.cs dosyasını değiştirmenize gerek yoktur. Varsayılan yönlendirmeye sahip olabilir.

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

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

{

// your code here

}

}

yukarıdaki yöntemi çağırmak için url aşağıdaki gibi olacaktır

http: // localhost: [portNo] / API / MyData / ReadMyData Param1 = deger1 & param2 = deger2 & param3 = deger3


İkinci seçeneği çok beğendim. VB.net'te nasıl kullanılacağını da bana gösterebilir misiniz? Çok teşekkürler.
user1617676

12

ASP.NET 5'i ASP.NET MVC 6 ile kullanıyorsanız , bu yanıtların çoğu işe yaramayacaktır çünkü normalde MVC'nin sizin için uygun rota koleksiyonunu oluşturmasına izin vereceksiniz (varsayılan RESTful kurallarını kullanarak), yani irade Routes.MapRoute()üzerinde düzenlenecek herhangi bir çağrı bulamazsınız .

ConfigureServices()Tarafından çağrılan yöntem Startup.csAradığınızda bu şekilde,: Dosya ASP.NET 5 yerleşik Bağımlılık Enjeksiyon çerçeve MVC kaydedecektir ApplicationBuilder.UseMvc()bu sınıfta daha sonra, MVC framework otomatik uygulamanıza bu varsayılan yolları ekleyecektir. UseMvc()Çerçeve kaynak kodundaki yöntem uygulamasına bakarak kaputun arkasında neler olduğuna bir göz atabiliriz :

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());
}

Bununla ilgili iyi olan şey, çerçevenin artık tüm zorlu işleri ele alması, tüm Denetleyicinin Eylemlerini yineleyerek ve varsayılan rotalarını ayarlayarak size fazladan iş tasarrufu sağlamasıdır.

Kötü olan, kendi rotalarınızı nasıl ekleyebileceğinizle ilgili çok az veya hiç belge olmamasıdır. Neyse ki, bunu Sözleşmeye Dayalı ve / veya Öznitelik Tabanlı bir yaklaşım (diğer adıyla Nitelik Yönlendirme ) kullanarak kolayca yapabilirsiniz .

Kongre Tabanlı

Startup.cs sınıfınızda şunu değiştirin:

app.UseMvc();

Bununla:

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" }
                );
            });

Özellik Tabanlı

MVC6 ile ilgili harika bir şey de, aşağıdaki gibi uygun ve / veya / veya şablon parametreleriyle Controllersınıf ve / veya Actionyöntemleri dekore ederek yolları denetleyici bazında tanımlayabilmenizdir :RouteAttributeHttpGetHttpPost

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!");
        }
    }
}

Bu denetleyici aşağıdaki istekleri yerine getirecektir:

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

Ayrıca, iki yaklaşımı bir arada kullanırsanız, Nitelik tabanlı rotaların (tanımlandığında) Konvansiyon temelli olanları geçersiz kılacağını ve her ikisinin de tarafından tanımlanan varsayılan rotaları geçersiz kılacağını unutmayın UseMvc().

Daha fazla bilgi için blogumdaki aşağıdaki yazıyı da okuyabilirsiniz .


1
Bu harika! Diğer cevapların hiçbiri aslında ihtiyacım olan şeyi yapmadı. Ama beni kurtardın :)
Kral Arthur Üçüncü

Önceden tanımlanmış bir modeli ikinci parametre olarak kullanmanın bir yolu var mı? Böyle belli bir kullanıcıyı bağlıyorum Örneğin,: public IActionResult Patch(int id, [FromQuery] Person person), tüm gelen özellikleri null!
Üçüncü Kral Arthur


0

WebAPIConfig.cs dosyanızı aşağıdaki gibi değiştirin

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

Ardından, API'nizi aşağıdaki gibi uygulayın

    // GET: api/Controller_Name/Show/1
    [ActionName("Show")]
    [HttpGet]
    public EventPlanner Id(int id){}

0

Web APi 2 ve sonraki sürümler, öznitelik yönlendirme adı verilen yeni bir yönlendirme türünü destekler. Adından da anlaşılacağı gibi, öznitelik yönlendirme, yolları tanımlamak için öznitelikleri kullanır. Öznitelik yönlendirme, web API'nizdeki URI'ler üzerinde size daha fazla kontrol sağlar. Örneğin, kaynakların hiyerarşilerini tanımlayan URI'leri kolayca oluşturabilirsiniz.

Örneğin:

[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }

Mükemmel olacak ve örneğin WebApiConfig.cs'de ekstra koda ihtiyacınız yok. Yalnızca WebApiConfig.cs'de web api yönlendirmesinin etkin olup olmadığından emin olmanız gerekir, yoksa aşağıdaki gibi etkinleştirebilirsiniz:

        // Web API routes
        config.MapHttpAttributeRoutes();

WebApiConfig.cs'de başka bir şey yapmanız veya bir şeyi değiştirmeniz gerekmez. Daha fazla ayrıntı için bu makaleye göz atabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.