在本文中,我们将详细介绍ASP.NETWebAPI中的自定义方法名称的各个方面,并为您提供关于asp.netwebapi设计的相关解答,同时,我们也将为您带来关于asp.netwebapi中的版本管理
在本文中,我们将详细介绍ASP.NET Web API中的自定义方法名称的各个方面,并为您提供关于asp.net web api设计的相关解答,同时,我们也将为您带来关于asp.net web api中的版本管理、ASP.NET WebAPI中的模拟和异步、ASP.Net WebAPI中的自定义路由处理程序、asp.net – 在Web API中获取匹配的路由名称的有用知识。
本文目录一览:- ASP.NET Web API中的自定义方法名称(asp.net web api设计)
- asp.net web api中的版本管理
- ASP.NET WebAPI中的模拟和异步
- ASP.Net WebAPI中的自定义路由处理程序
- asp.net – 在Web API中获取匹配的路由名称
ASP.NET Web API中的自定义方法名称(asp.net web api设计)
我正在从WCF Web API转换为新的ASP.NET MVC 4 Web
API。我有一个UsersController,我想有一个名为Authenticate的方法。我看到了有关如何执行GetAll,GetOne,Post和Delete的示例,但是如果我想在这些服务中添加其他方法怎么办?例如,我的UsersService应该有一个称为Authenticate的方法,他们在其中传递用户名和密码,但这是行不通的。
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 /,它将调用GetAll,我可以浏览到myapi / api / users /
1,并且它将调用Get,但是,如果我调用myapi / api / users / authenticate?username = {0}
&password = {1},然后它将调用Get(不进行身份验证)并报错:
参数字典包含用于’Navtrak.Services.WCF.NavtrakAPI.Controllers.UsersController’中方法’System.String
Get(Int32)’的非空类型’System.Int32’的参数’id’的空条目。可选参数必须是引用类型,可为空的类型,或者必须声明为可选参数。
如何调用自定义方法名称,例如Authenticate?
答案1
小编典典默认情况下,路由配置遵循RESTFul约定,这意味着它将仅接受Get,Post,Put和Delete操作名称(默认情况下,请查看global.asax
=>中的路由,不允许您指定任何操作名称=>它使用HTTP动词进行分派)。因此,当您向GET请求发送消息时,/api/users/authenticate
您基本上是在调用该Get(intid)
操作并传递id=authenticate
,这显然会崩溃,因为您的Get操作需要一个整数。
如果您希望使用与标准名称不同的动作名称,则可以在global.asax
以下位置修改路径定义:
Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { action = "get", id = RouteParameter.Optional });
现在,您可以导航到/api/values/getauthenticate
以验证用户身份。
asp.net web api中的版本管理
应用是演进的,通常我们用版本号来管理。api也是演进的,这篇博文就说说asp.net web api演进时的版本管理。
asp.net web api的版本管理是通过微软的一个包来实现的。
Install-Package Microsoft.AspNetCore.Mvc.Versioning
通过url参数: apI/Order/api-version=2.0
在startup中注入ApiVersion
public void ConfigureServices(IServiceCollection services) { services.AddApiVersioning(); services.AddControllers(); }
在ProductController中标注版本特性
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace APIVersionDemo.Controllers { [ApiController] [Route("api/[controller]")] [ApiVersion("1.0", Deprecated = true)] [ApiVersion("2.0")] public class ProductController : ControllerBase { private readonly ILogger<ProductController> _logger; public ProductController(ILogger<ProductController> logger) { _logger = logger; } //1.0的api [HttpGet("{id}")] public Product QueryProduct([Fromroute] int id) { _logger.Loginformation("v1.0查询产品"); return new Product() { ID = id, Name = "A物品", Price = 100.20m }; } //2.0的api [HttpGet("{id}")] [MapToApiVersion("2.0")] public Product QueryProductv2([Fromroute] int id) { _logger.Loginformation("v2.0查询产品"); return new Product2() { ID = id, Name = "A物品", Price = 100.20m, Description = "产自山西" }; } } /// <summary> /// 1.0的产品类 /// </summary> public class Product { public int ID { get; set; } public string Name { get; set; } public decimal Price { get; set; } } /// <summary> /// 2.0的产品类 /// </summary> public class Product2 : Product { public string Description { get; set; } } }
通过http://localhost:5000/api/product/1?api-version=2.0方式访问不同的版本。显而易见,这种通过在请求url末尾加参数的方式有点啰嗦。
通过MediaType:{Accept:application/json;version=2.0}或header:{version:2.0}
修改startup的apiversion注入参数
public void ConfigureServices(IServiceCollection services) { services.AddApiVersioning(opt => { opt.AssumeDefaultVersionWhenUnspecified = true; opt.DefaultApiVersion = new ApiVersion(1, 0); opt.ApiVersionReader = ApiVersionReader.Combine( new MediaTypeApiVersionReader("version"), new HeaderApiVersionReader("api-version") ); opt.ReportApiVersions = true; }); services.AddControllers(); }
ProductController不变。
请求http://localhost:5000/api/product/1,header参数,可以适配两种方式:Accept : application/json;version=2.0api-version : 2.0
这样方便客户端请求的整体处理。
通过url:api/v2.0/order
strartup.cs注入apiversion
public void ConfigureServices(IServiceCollection services) { services.AddApiVersioning(); services.AddControllers(); }
这里引入OrderController,在Route特性上改变url,在url里增加版本信息{version:apiVersion}
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace APIVersionDemo.Controllers { [ApiController] [Route("api/v{version:apiVersion}/[controller]")] [ApiVersion("1.0", Deprecated = true)] [ApiVersion("2.0")] public class OrderController : ControllerBase { private readonly ILogger<OrderController> _logger; public OrderController(ILogger<OrderController> logger) { _logger = logger; } //v1订单api [HttpGet("{id}")] public Order QueryOrder() { _logger.Loginformation("v1查询产品"); return new Order() { OrderID = 1, Products = new List<Product>() { new Product() { ID = 1, Name = "A物品", Price = 100.20m } } }; } //v2订单api [HttpGet("{id}")] [MapToApiVersion("2.0")] public Order2 QueryOrder2() { _logger.Loginformation("v2查询产品"); return new Order2() { OrderID = 1, Products = new List<Product2>() { new Product2() { ID = 1, Name = "A物品", Price = 100.20m, Description = "产自山西" } } }; } } //v1订单类 public class Order { public int OrderID { get; set; } public List<Product> Products { get; set; } } //v2订单类 public class Order2 { public int OrderID { get; set; } public List<Product2> Products { get; set; } } }
这时请求就变成http://localhost:5000/api/v2.0/order了,可以通过不同的url来访问不同的api版本,这种方式也有利于客户端统一配置baseurl,来切换请求api版本。
最后,apiversion这个包还带来了一个无侵入controller的方式来配置api的版本,本质与加在Controller上的特性信息是一致的——附加版本信息和对应关系。
services.AddApiVersioning(opt => { opt.Conventions.Controller<ProductController>() .HasApiVersion(2, 0) .HasDeprecatedApiVersion(1, 0) .Action(typeof(ProductController) .getmethod(nameof(ProductController.QueryProductv2))!) .MapToApiVersion(2, 0); });
想要更快更方便的了解相关知识,可以关注微信公众号
ASP.NET WebAPI中的模拟和异步
这个问题最初是“模仿是否适用于Web API?”
对这个问题的问题是“是的,确实如此”.
但问题不在于Web API,而在于模仿本身. (问题的描述如下)
但现在我想告诉其他人解决方案.
我的控制器是异步的,我错误的前提是模拟线程产生的任何线程都与其父线程具有相同的身份.
默认情况下为false:TPL不会跨线程进行模拟.
模拟流程可以启用programmatically or in configuration.
请注意,应该对aspnet.config文件进行更改,而不是对应用程序的web.config进行更改.
正如this post所述,每个应用程序池都可以设置aspnet.config文件.
this post安德鲁亲切地提供了关于更详细的整个任务的链接.
对于那些第一次打开模拟的人,我想要注意IIS 7.5有一个非常好的功能来输入模拟帐户的凭据.配置文件中不需要这些凭据,只能写入.
<identity impersonate="true"/>
输入凭据后,它们将自动添加到配置文件中.
原始问题:
我转而模仿并提供了用户凭据.
<identity impersonate="true" usernName="foo" password="bar"/>
但是当我通过Entity Framework连接到sql server时,我收到错误“用户{MachineName} $登录失败”.那就是EF在IUSR账户下运行.同时,WindowsIdentity.GetCurrent()返回’foo’用户的身份.
模拟帐户在启用了Windows身份验证的sql服务器上具有所有必需权限.
此外,如果我禁用模拟并只设置应用程序池以使用此标识的凭据运行,一切正常.
我无法理解为什么在模拟开启时它不起作用但AppPool在默认帐户下运行.
更新1
EF连接字符串是
<add name="PtKbEntities" connectionString="Metadata=...;provider=System.Data.sqlClient;provider connection string="data source=...;initial catalog=...;Trusted_Connection=Yes;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
我在Win2008 Srv,IIS 7.5上托管应用程序
解决方法
在我看来,有一个很好的解释here使用哪一个:模仿或应用程序池
ASP.Net WebAPI中的自定义路由处理程序
routes.MapHttpRoute( name: "DefaultApi",routeTemplate: "{client}/api/1.0/{controller}/{action}/{id}",defaults: new{id = UrlParameter.Optional} ).RouteHandler = new SingleActionAPIRouteHandler();
但是,当我调用HttpConfiguration.Routes.MapRoute我无法在返回的IHttpRoute上设置一个处理程序时,我试图在内存主机中设置API进行集成测试时似乎找不到一种方法.
我应该做的不同(例如通过使用自定义HttpControllerSelector)?我显然希望在这两种情况下都这样做.
谢谢,
马特
编辑:
所以我最后做的是基本上遵循下面的建议,但只是覆盖HttpControllerdispatcher类,如下所示:
public class CustomHttpControllerdispatcher : HttpControllerdispatcher { public CustomHttpControllerdispatcher(HttpConfiguration configuration) : base(configuration) { } protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken) { // My stuff here return base.SendAsync(request,cancellationToken); } }
解决方法
更新:更清楚一点
你应该几乎肯定会使用HttpControllerSelector并实现一个自定义的…一个例子是. http://netmvc.blogspot.co.uk/
以下是一些实验,如果HttpControllerSelector不足以满足您的要求,什么原因…
但是,正如你可以看到MapHttpRoute对HttpMessageHandler有一个重载,所以你可以试试这个… if the handler is NULL then it defaults to IHttpController,但你可以实现自己的,并使用它来指导正确的控制器… MVC框架似乎使用[HttpControllerdispatcher ] here,所以借用一些代码,你可以在这里放置自己的控制器/路由选择代码 – 你可以访问路由和选择器,并可以自己交换它.
这个CustomHttpControllerdispatcher代码仅用于DEMO …查找该行
//DO SOMETHING CUSTOM HERE TO PICK YOUR CONTROLLER
也许有一个玩…
示例路线:
config.Routes.MapHttpRoute( name: "DefaultApi",routeTemplate: "api/{controller}/{id}",defaults: new { id = RouteParameter.Optional },constraints: null,handler: new CustomHttpControllerdispatcher(config) );
示例CustomHttpControllerdispatcher:
public class CustomHttpControllerdispatcher : HttpMessageHandler { private IHttpControllerSelector _controllerSelector; private readonly HttpConfiguration _configuration; public CustomHttpControllerdispatcher(HttpConfiguration configuration) { _configuration = configuration; } public HttpConfiguration Configuration { get { return _configuration; } } private IHttpControllerSelector ControllerSelector { get { if (_controllerSelector == null) { _controllerSelector = _configuration.Services.GetHttpControllerSelector(); } return _controllerSelector; } } protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken) { return SendAsyncInternal(request,cancellationToken); } private Task<HttpResponseMessage> SendAsyncInternal(HttpRequestMessage request,CancellationToken cancellationToken) { IHttpRouteData routeData = request.GetRouteData(); Contract.Assert(routeData != null); //DO SOMETHING CUSTOM HERE TO PICK YOUR CONTROLLER HttpControllerDescriptor httpControllerDescriptor = ControllerSelector.SelectController(request); IHttpController httpController = httpControllerDescriptor.CreateController(request); // Create context HttpControllerContext controllerContext = new HttpControllerContext(_configuration,routeData,request); controllerContext.Controller = httpController; controllerContext.ControllerDescriptor = httpControllerDescriptor; return httpController.ExecuteAsync(controllerContext,cancellationToken); } }
asp.net – 在Web API中获取匹配的路由名称
public class CurrentRequestMessageHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken) { var route = request.GetRouteData().Route; //Now what? return base.SendAsync(request,cancellationToken); } }
解决方法
更新 – 2014年6月23日
通过属性路由领域的最新改进(5.2 RC),您可以执行以下操作,将路径名称插入到数据令牌中.
config.MapHttpAttributeRoutes(new CustomDefaultDirectRouteProvider()); public class CustomDefaultDirectRouteProvider : DefaultDirectRouteProvider { public override IReadOnlyList<RouteEntry> GetDirectRoutes(HttpControllerDescriptor controllerDescriptor,IReadOnlyList<HttpActionDescriptor> actionDescriptors,IInlineConstraintResolver constraintResolver) { IReadOnlyList<RouteEntry> coll = base.GetDirectRoutes(controllerDescriptor,actionDescriptors,constraintResolver); foreach(RouteEntry routeEntry in coll) { if (!string.IsNullOrEmpty(routeEntry.Name)) { routeEntry.Route.DataTokens["Route_Name"] = routeEntry.Name; } } return coll; } }
像这样访问它:reequest.GetRouteData().Route.DataTokens [ “ROUTE_NAME”]
我们今天的关于ASP.NET Web API中的自定义方法名称和asp.net web api设计的分享已经告一段落,感谢您的关注,如果您想了解更多关于asp.net web api中的版本管理、ASP.NET WebAPI中的模拟和异步、ASP.Net WebAPI中的自定义路由处理程序、asp.net – 在Web API中获取匹配的路由名称的相关信息,请在本站查询。
本文标签: