Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/270.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将Web Api控制器优先于IHttpHandler?_C#_Asp.net_Asp.net Mvc_Asp.net Web Api_Httphandler - Fatal编程技术网

C# 如何将Web Api控制器优先于IHttpHandler?

C# 如何将Web Api控制器优先于IHttpHandler?,c#,asp.net,asp.net-mvc,asp.net-web-api,httphandler,C#,Asp.net,Asp.net Mvc,Asp.net Web Api,Httphandler,我有一个遗留项目,它有一个IHttpHandler实现类,使用一个巨大的switch语句等路由所有请求。。我试图用apicontroller引入属性路由,但第一个始终具有优先级。是否可以配置系统(代码或IIS),使Web APIController优先于我的单个IHttpHandler实现类?在IIS中,我将我的AttributeRouting放在第一位,然后是所有的aspx,但仍然没有首先处理Web Api控制器。无论我做什么(将它们放在同一个项目下)。我不想引入一个单独的项目 编辑:有一个I

我有一个遗留项目,它有一个IHttpHandler实现类,使用一个巨大的switch语句等路由所有请求。。我试图用apicontroller引入属性路由,但第一个始终具有优先级。是否可以配置系统(代码或IIS),使Web APIController优先于我的单个IHttpHandler实现类?在IIS中,我将我的AttributeRouting放在第一位,然后是所有的aspx,但仍然没有首先处理Web Api控制器。无论我做什么(将它们放在同一个项目下)。我不想引入一个单独的项目

编辑:有一个IHTTP模块,它根据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
 }




我找到了两种解决这个问题的方法。第一个是通过插入检查WebAPI路由系统是否能够处理请求来修改重写URL的模块。第二个是向应用程序添加另一个模块,该模块将使用
HttpContext.RemapHandler()
将请求定向到Web API处理程序

以下是代码:

第一个解决方案。

如果您的模块如下所示:

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");
            }
        };
    }
}
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");
        }
    };
}
然后您需要像这样更改它:

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");
            }
        };
    }
}
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");
        }
    };
}
第二种解决方案。

用于重新映射处理程序的模块:

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));
                }
            }
        };
    }
}
当method
WebApiConfig.Register
为空时,这些解决方案可以工作,但如果存在带有模板的路由,如
“api/{controller}”
,则任何带有以“api”开头的两个段的路径都将通过检查,即使没有具有指定名称的控制器,并且您的模块可以对该路径执行用户完全的操作。例如,在这种情况下,您可以使用answer中的方法来检查控制器是否存在

此外,即使找到的控制器不处理当前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";
    }
}

HttpHandlers
在命中api控制器之前工作。处理程序用于检查并可能拦截或重定向给定的资源请求。反过来也不行。您必须从处理程序的switch语句中取出
default
,才能使其正常工作。但是,您可以对web api执行相同的操作—您可以显式指定配置中的所有可用路由,并使用默认路由将它们带到返回错误的路由。现在我已经考虑了一下,您可以检查配置的api路由并让它们通过。现在我想尝试一下…@ps2goat我可以有一个HttpModule来代替我的ApiController吗?虽然我不知道这会是怎样的。我希望这不会对性能造成影响。在这一点上,模块的行为就像IIS和web api中的内置url路由一样。这是一个单一的问题还是整个网站都有这个问题?完整的故事是,有一个模块根据url路由到不同的ashx。所以这是网站的一部分。我想覆盖所有这些,当我调用api/endpoint3/将其重新路由到apicontroller或其他东西时,或者如果有助于区分它的话,可以使用类似api/rest/endpoint3的东西时。。。这回答了你的问题吗?谢谢你的努力!我认为你有点误解了这一点,但我稍后会仔细阅读答案。。我有3个模块,其中一个重定向到/api/,它通过resource.aspx(HttpHandler)处理它支持的所有情况。。。但是我有3个web api控制器,我希望它们在流量到达Resource.aspx之前处理流量。。在您的代码中,所有这些端点1、2、3都指向Resource.aspx,这已经发生了,我不希望它发生。..@MichailMichailidis我仍然不明白。您可以在执行Resource.aspx中的HttpHandler之前阻止重定向到模块中的/api/或回滚此重定向。这不是你所需要的吗?我编辑了这个问题以使其更加清晰-并且在httpmodule中添加了一条注释。。如果仍然不清楚,请告诉我-谢谢-问题是任何重定向到/api/。。。将再次点击模块,过程将再次开始。@MichailMichailidi很抱歉我的固执,我仍然不明白。如果调用了PostResolveRequestCache事件HttpContext.RewritePath(只重写一些上下文变量)和HttpContext.RemapHandler(使用Web API处理程序作为参数),则Web API框架只处理请求。它不会再进入模块中的BeginRequest事件。我知道您在第二个解决方案中试图做什么。当我读到第一个解决方案时,还不清楚。那么,当httphandler和web api控制器分别处理冲突的/api/endpoint0,1,2和api/endpoint3时,您能够测试它并使其工作吗?
[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";
    }
}