Mic*_*dis 8 c# asp.net asp.net-mvc httphandler asp.net-web-api
我有一个遗留项目有一个IHttpHandler实现类,使用一个巨大的switch语句等路由所有请求.我试图引入属性路由与ApiControllers,但第一个始终具有优先级.是否可以配置系统(代码或IIS),以便Web ApiControllers优先于我的单个IHttpHandler实现类?在IIS中,我首先放置了我的AttributeRouting,然后是所有的aspx,但仍然没有首先处理Web Api控制器.无论我做什么(在同一个项目下都有它们).我不想介绍一个单独的项目.
编辑:有一个IHttpModule根据api /之后的内容决定将其路由到特定的ashx文件.其中一个是描述的..
编辑2:更具体地说:如果uri没有过滤的东西列表[文件,消息,属性...],它将被路由到Resource.aspx
所以api/file,api/message,api/property将从其他.ashx文件中处理 - 否则流量将转到Resource.ashx ...
因此,具有api/endpoint1,api/endpoint2,api/endpoint3的请求都将转到Resource.aspx.问题是如何将api/endpoint3路由到下面描述的API控制器.谢谢
简化的代码架构:
//SolutionName/Api/MyModule.cs (Legacy Code)
//this routes based on what is after api/ to Resource.ashx or other ashx files
public class MyModule : IHttpModule {
//if url doesn't contain [file,message,property ...] route to Resource.ashx
}
Run Code Online (Sandbox Code Playgroud)
//SolutionName/API/Resource.ashx (Legacy Code)
//this is hit at any request solutionname/api/anything
public class DefaultHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context) {
String APIBranch = parse(context);
switch(APIBranch)
{
case "endpoint1": methodOne(); break;
case "endpoint2": methodTwo(); break;
[...]
default: throw Exception(); break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
//SolutionName/API/App_Start/AttributeRoutingHttpConfig.cs
public static class AttributeRoutingHttpConfig
{
public static void RegisterRoutes(HttpRouteCollection routes)
{
// See http://github.com/mccalltd/AttributeRouting/wiki for more options.
// To debug routes locally using the built in ASP.NET development server, go to /routes.axd
routes.MapHttpAttributeRoutes();
}
public static void Start()
{
RegisterRoutes(GlobalConfiguration.Configuration.Routes);
}
}
Run Code Online (Sandbox Code Playgroud)
//SolutionName/API/Controllers/MyController.cs
//this should have been hit for a GET on solutionname/api/endpoint3/id
[RoutePrefix("endpoint3")]
public class MyController : ApiController
{
private IModelDao modelDao;
MyController(IModelDao modelDao){
this.modelDao = modelDao;
}
[Route("{id}")]
[HttpGet]
public Model GetSomething(int id)
{
Model model = modelDao.GetSomething(id);
return model;
}
}
Run Code Online (Sandbox Code Playgroud)
我找到了解决这个问题的两种方法。第一个是通过插入检查 Web API 路由系统是否可以处理请求来修改重写 url 的模块。第二个是向应用程序添加另一个模块,该模块将使用HttpContext.RemapHandler()
.
这是代码:
第一个解决方案。
如果您的模块如下所示:
public class MyModule: IHttpModule
{
public void Dispose(){}
public void Init(HttpApplication context)
{
context.BeginRequest += (object Sender, EventArgs e) =>
{
HttpContext httpContext = HttpContext.Current;
string currentUrl = httpContext.Request.Url.LocalPath.ToLower();
if (currentUrl.StartsWith("/api/endpoint0") ||
currentUrl.StartsWith("/api/endpoint1") ||
currentUrl.StartsWith("/api/endpoint2"))
{
httpContext.RewritePath("/api/resource.ashx");
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
然后你需要像这样改变它:
public void Init(HttpApplication context)
{
context.BeginRequest += (object Sender, EventArgs e) =>
{
HttpContext httpContext = HttpContext.Current;
var httpRequestMessage = new HttpRequestMessage(
new HttpMethod(httpContext.Request.HttpMethod),
httpContext.Request.Url);
IHttpRouteData httpRouteData =
GlobalConfiguration.Configuration.Routes.GetRouteData(httpRequestMessage);
if (httpRouteData != null) //enough if WebApiConfig.Register is empty
return;
string currentUrl = httpContext.Request.Url.LocalPath.ToLower();
if (currentUrl.StartsWith("/api/endpoint0") ||
currentUrl.StartsWith("/api/endpoint1") ||
currentUrl.StartsWith("/api/endpoint2"))
{
httpContext.RewritePath("/api/resource.ashx");
}
};
}
Run Code Online (Sandbox Code Playgroud)
第二个解决方案。
重新映射处理程序的模块:
public class RemappingModule: IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication context)
{
context.PostResolveRequestCache += (src, args) =>
{
HttpContext httpContext = HttpContext.Current;
string currentUrl = httpContext.Request.FilePath;
if (!string.IsNullOrEmpty(httpContext.Request.QueryString.ToString()))
currentUrl += "?" + httpContext.Request.QueryString;
//checking if url was rewritten
if (httpContext.Request.RawUrl != currentUrl)
{
//getting original url
string url = string.Format("{0}://{1}{2}",
httpContext.Request.Url.Scheme,
httpContext.Request.Url.Authority,
httpContext.Request.RawUrl);
var httpRequestMessage = new HttpRequestMessage(
new HttpMethod(httpContext.Request.HttpMethod), url);
//checking if Web API routing system can find route for specified url
IHttpRouteData httpRouteData =
GlobalConfiguration.Configuration.Routes.GetRouteData(httpRequestMessage);
if (httpRouteData != null)
{
//to be honest, I found out by experiments, that
//context route data should be filled that way
var routeData = httpContext.Request.RequestContext.RouteData;
foreach (var value in httpRouteData.Values)
routeData.Values.Add(value.Key, value.Value);
//rewriting back url
httpContext.RewritePath(httpContext.Request.RawUrl);
//remapping to Web API handler
httpContext.RemapHandler(
new HttpControllerHandler(httpContext.Request.RequestContext.RouteData));
}
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
这些解决方案在方法WebApiConfig.Register
为空时有效,但如果存在带有模板的路由,那么"api/{controller}"
任何具有以“api”开头的两个段的路径都会通过检查,即使没有具有指定名称的控制器,并且您的模块可以执行一些有用的操作这条路。例如,在这种情况下,您可以使用此答案中的方法来检查控制器是否存在。
即使发现控制器不处理当前 http 方法的请求,Web API 路由系统也会接受路由。RouteFactoryAttribute
您可以使用和的后代HttpMethodConstraint
来避免这种情况。
UPD在此控制器上测试:
[RoutePrefix("api/endpoint1")]
public class DefaultController : ApiController
{
[Route("{value:int}")]
public string Get(int value)
{
return "TestController.Get: value=" + value;
}
}
[RoutePrefix("api/endpoint2")]
public class Endpoint2Controller : ApiController
{
[Route("segment/segment")]
public string Post()
{
return "Endpoint2:Post";
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1212 次 |
最近记录: |