【问题标题】:URL rewrite in ASP.NET 4.5 and Web APIASP.NET 4.5 和 Web API 中的 URL 重写
【发布时间】:2013-04-16 22:17:20
【问题描述】:

我们有一个长期运行的 ASP.NET Web 表单应用程序,它诞生于 .NET 1.1/IIS6 时代。我们现在在 .NET4.5/IIS7 上,但我们没有对 MVC 做任何事情。

我们向客户提供目录并为他们提供可以使用的 URL:

www.ourhost.com/customername

使用我们开发的自定义 IHttpModule,我们从 URL 中提取“customername”以在数据库中查找客户。然后将该客户的 ID 存储在页面的上下文中*,并由站点上的几乎所有页面用于为该客户定制内容。在这个过程之后,上面的 URL 将被重写并处理为

www.ourhost.com/index.aspx

index.aspx 可以通过其上下文访问客户的 ID,它可以做它的事情。

这很好用,我们为数千名客户提供支持。重写逻辑相当复杂,因为它会验证客户帐户,如果客户无效则重定向到“哦哦”页面,如果客户未付款则重定向到不同的“查找经销商”页面等等。

现在我想构建一些 Web API 控制器,而 MVC 风格的重写让我很担心。我看到很多例子,其中重写恰好使 URL 像这样工作:

www.ourhost.com/api/{controller}

但我仍然需要在客户的上下文中发生这些 web api“调用”。我们的页面使用 JSON/AJAX 异步调用变得更加复杂,但在应答这些调用时,我仍然需要客户上下文。我希望网址是

www.ourhost.com/customername/api/{controller}

但是对于如何配置路由来做到这一点并让它与我们的 IHttpModule 很好地配合,我感到很困惑。

这甚至可能吗?

*更新:当我说“存储在页面上下文中”时,我指的是与每个 Web 请求相关联的 HttpContext,其中包括一个字典,我可以在其中存储一些页面/请求特定的数据。

【问题讨论】:

  • 当你说“存储在页面的上下文中”时——你是指Session 对象,还是直接写给某种Cookie?既然你标记了这个web-api,它就有点不同了。
  • @Troy:感谢您的评论 - 我已经更新了我的问题并进行了澄清。
  • 知道了 - 您正在使用 HttpContext.Current.User 来跟踪您的登录用户是谁?您如何将其持久化到 URL 中不包含用户用户名的后续调用中?

标签: asp.net-mvc-4 asp.net-mvc-routing asp.net-web-api


【解决方案1】:

我可以看到您的问题的答案有两个部分。

跨多个请求维护用户信息 通常,MVC API 应用程序将是无状态的,即您不保留请求之间的当前用户会话状态。嗯,这就是我在编写 RESTFul API 时学到或被多次宣扬的。

也就是说,您可以通过将以下内容添加到 global.asax.cs 来启用 MVC Web API 中的会话状态

    protected void Application_PostAuthorizeRequest()
    {
        // To enable session state in the WebAPI.
        System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
    }

在请求中授权客户 正如您在请求 URL 中显示的那样,您可以添加客户名称,然后捕获该名称并将其传递给当前 http 模块调用以根据请求进行授权的同一例程。您可以使用 MVC 过滤器来做到这一点。

首先做一个类似的 URL 模式以在 WebApiConfig.cs 中捕获您的客户名称,类似这样;

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

然后将 ActionFilter 添加到您的 API 控制器,该控制器处理每个请求,检查当前会话信息,并在需要时调用您的授权/客户查找代码,然后保存到会话状态以供以后使用。或者如果客户没有好的信息可以发送到新的 MVC 路由

所以你会添加一个类似这样的属性;

[WebApiAuthentication]
public class BaseApiController : ApiController
{
}

然后创建一个可能看起来像这样的操作过滤器(注意我没有测试过这个,只是为了一个如何做的模式)。

public class WebApiAuthenticationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var routeData = actionContext.ControllerContext.Request.GetRouteData();
        var currentContext = HttpContext.Current;

        if (routeData.Route.RouteTemplate.Contains("customername"))
        {
            try
            {
                var authenticated = currentContext.Request.IsAuthenticated;
                if (!authenticated)
                {
                    var customer = routeData.Values["customername"];
                    // do something with customer here and then put into session or cache
                    currentContext.Session.Add("CustomerName", customer);
                }
            }
            catch (Exception exception)
            {
                var error = exception.Message;
                // We dont like the request
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest);
            }
        }
        else
        {
            // No customer name specified, send bad request, not found, what have you ... you *could* potentially redirect but we are in API so it probably a service request rather than a user
            actionContext.Response = new HttpResponseMessage(HttpStatusCode.NotFound);
        }

    }
}

如果您创建一个新的 MVC 5 Web API 应用程序并添加这些附加功能并将过滤器放在默认值控制器上,那么您应该能够看到它作为可能解决方案的演示运行。

如果一切正常,这将回显客户名称。

[WebApiAuthentication]
public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        var session = HttpContext.Current.Session;

        if (session != null)
        {
            return new string[] {"session is present", "customer is", session["CustomerName"].ToString()};
        }

        return new string[] { "value1", "value2" };
    }

}

正如我所说,我提供了一个可能的解决方案,关于在 API 中存储会话和授权存在宗教争论,但这些不是问题所在。 希望有帮助, 史蒂夫

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-24
    • 2013-02-21
    • 2015-06-29
    • 2011-08-24
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多