ASP.NET的Web API RTM和子路径 [英] ASP.NET Web API RTM and subdomain routes

查看:182
本文介绍了ASP.NET的Web API RTM和子路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有越来越的Web API问题与基于子域的路由工作。总之,我得到的权利控制器和控制方法,但数据令牌出了子由的WebAPI没有被拾起。

I am having issues getting Web API to work with subdomain-based routes. In short, I am getting to the right controller and method but the data token out of the subdomain is not being picked up by WebAPI.

我有这在我的情况:

contoso.myapp.com
fabrikam.myapp.com
{tenant}.myapp.com

所有解决相同的ApiController,我希望能够提取 {租户} 标记。

我用code这篇文章的http://blog.maartenballiauw.be/post/2012/06/18/Domain-based-routing-with-ASPNET-Web-API.aspx

I used the code in this article http://blog.maartenballiauw.be/post/2012/06/18/Domain-based-routing-with-ASPNET-Web-API.aspx

但是,似乎该文章写和ASP.NET网页API出去公测时间之间已经改变了一些东西。在文章中的code为依托 RouteTable.Routes ,而在网页API路由通过 HttpConfiguration.Routes 这是一个 HttpRouteCollection ,而不是通常的 RouteCollection (它派生自 RouteCollection 实际上)。

But there is something that seem to have changed between the time the article was written and ASP.NET Web Api went out of beta. The code in the article is relying on RouteTable.Routes while on Web API routes are configured through HttpConfiguration.Routes which is an HttpRouteCollection and not the usual RouteCollection (it derives from RouteCollection actually).

于是,我改变了code从 HttpRoute 派生,而不是路线。这里是code:

So I changed the code to derive from HttpRoute instead of Route. Here is the code:

https://gist.github.com/3766125

我配置这样的路线

 config.Routes.Add(new HttpDomainRoute(
            name: "test",
            domain: "{tenant}.myapp.com",
            routeTemplate: "test",
            defaults: new { controller = "SomeController", action = "Test" }
        ));

和我的请求路由到正确的控制器。但是,承租人数据令牌是从来没有填充(如果我做 this.Request.GetRouteData()我看到控制器和动作令牌而不是租客)。如果我把一个断点 GetRouteData 它永远不会被调用。

And my requests are routed to the right controller. However, the tenant data token is never filled (if I do this.Request.GetRouteData() I see the controller and action tokens but not tenant). If I put a breakpoint on GetRouteData it is never called.

我试图按照与反射器code路径和看到GetRouteData被调用在HttpRouteCollection水平,但似乎集合enumarating是空的。不知道究竟是如何定期ASP.NET路由和Web API路由之间的集成桥,但它是混淆了我。

I tried to follow the code path with reflector and see where GetRouteData is being called at the HttpRouteCollection level, but it seems that the collection is enumarating is empty. Not sure exactly how the integration between regular ASP.NET routing and WEb API routing is bridged but it is confusing me.

任何想法?

我现在使用的解决方法是显式调用GetRouteData在路线

The workaround I am using for now is calling explicitly GetRouteData over the Route

this.Request.GetRouteData()。Route.GetRouteData(this.Request.RequestUri.ToString(),this.Request)

推荐答案

这更多的思考之后,我对你有一种变通方法。解决方法的基本思想是使用从路线派生的路线,并将其直接添加到RouteCollection。这样,我们传递的路线将不再里面HttpWebRoute包裹。

After thinking of this more, I have a workaround for you. The basic idea of the workaround is to use a route that derives from Route and add it to the RouteCollection directly. That way, the route we are passing will no longer be wrapped inside HttpWebRoute.

该RouteByPassing处理程序是要解决的另一个已知的问题。希望这有助于。

The RouteByPassing handler is to workaround another known issue. Hope this helps.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        RouteTable.Routes.Add("test", new HttpDomainRoute(
            domain: "{tenant}.auth10.com",
            routeTemplate: "test",
            defaults: new { controller = "Values", action = "GetTenant" }
        ));

        config.MessageHandlers.Add(new RouteByPassingHandler());
    }
}

public class RouteByPassingHandler : DelegatingHandler
{
    protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        HttpMessageInvoker invoker = new HttpMessageInvoker(new HttpControllerDispatcher(request.GetConfiguration()));
        return invoker.SendAsync(request, cancellationToken);
    }
}

public class HttpDomainRoute
    : Route
{
    private Regex domainRegex;
    private Regex pathRegex;

    public HttpDomainRoute(string domain, string routeTemplate, object defaults, object constraints = null)
        : base(routeTemplate, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), new RouteValueDictionary(), HttpControllerRouteHandler.Instance)
    {
        this.Domain = domain;
    }

    public string Domain { get; set; }

    public override RouteData GetRouteData(HttpContextBase context) 
    {   
        // Build regex
        domainRegex = CreateRegex(this.Domain);
        pathRegex = CreateRegex(this.Url);

        // Request information
        string requestDomain = context.Request.Headers["Host"];
        if (!string.IsNullOrEmpty(requestDomain))
        {
            if (requestDomain.IndexOf(":") > 0)
            {
                requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":"));
            }
        }
        else
        {
            requestDomain = context.Request.Url.Host;
        }

        string requestPath = context.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + context.Request.PathInfo;

        // Match domain and route
        Match domainMatch = domainRegex.Match(requestDomain);
        Match pathMatch = pathRegex.Match(requestPath);

        // Route data
        RouteData data = null;
        if (domainMatch.Success && pathMatch.Success)
        {
            data = base.GetRouteData(context);

            // Add defaults first
            if (Defaults != null)
            {
                foreach (KeyValuePair<string, object> item in Defaults)
                {
                    data.Values[item.Key] = item.Value;
                }
            }

            // Iterate matching domain groups
            for (int i = 1; i < domainMatch.Groups.Count; i++)
            {
                Group group = domainMatch.Groups[i];
                if (group.Success)
                {
                    string key = domainRegex.GroupNameFromNumber(i);

                    if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
                    {
                        if (!string.IsNullOrEmpty(group.Value))
                        {
                            data.Values[key] = group.Value;
                        }
                    }
                }
            }

            // Iterate matching path groups
            for (int i = 1; i < pathMatch.Groups.Count; i++)
            {
                Group group = pathMatch.Groups[i];
                if (group.Success)
                {
                    string key = pathRegex.GroupNameFromNumber(i);

                    if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
                    {
                        if (!string.IsNullOrEmpty(group.Value))
                        {
                            data.Values[key] = group.Value;
                        }
                    }
                }
            }
        }

        return data;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) 
    {
        return base.GetVirtualPath(requestContext, RemoveDomainTokens(values));
    }

    private Regex CreateRegex(string source)
    {
        // Perform replacements
        source = source.Replace("/", @"\/?");
        source = source.Replace(".", @"\.?");
        source = source.Replace("-", @"\-?");
        source = source.Replace("{", @"(?<");
        source = source.Replace("}", @">([a-zA-Z0-9_-]*))");

        return new Regex("^" + source + "$");
    }

    private RouteValueDictionary RemoveDomainTokens(RouteValueDictionary values)
    {
        Regex tokenRegex = new Regex(@"({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?({[a-zA-Z0-9_-]*})*-?\.?\/?");
        Match tokenMatch = tokenRegex.Match(Domain);
        for (int i = 0; i < tokenMatch.Groups.Count; i++)
        {
            Group group = tokenMatch.Groups[i];
            if (group.Success)
            {
                string key = group.Value.Replace("{", "").Replace("}", "");
                if (values.ContainsKey(key))
                    values.Remove(key);
            }
        }

        return values;
    }
}

}

这篇关于ASP.NET的Web API RTM和子路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆