【问题标题】:DateTime custom Model Binder for database multilanguage routing用于数据库多语言路由的 DateTime 自定义模型绑定器
【发布时间】:2018-01-16 18:12:36
【问题描述】:

我有一个带有自定义数据库路由的应用程序:

routes.Add("RouteWeb", new RouteWeb());

public override RouteData GetRouteData(HttpContextBase httpContext)
{
    if (httpContext.Request.IsAjaxRequest() || httpContext.Request.Url == null) return null;

    var page = FindPageFromDataBase(httpContext.Request.Url);
    if (page == null) return null;

    var pageResult = new RouteData(this, new MvcRouteHandler());
    pageResult.Values["culture"] = page.Culture;
    pageResult.Values["controller"] = page.controller;
    pageResult.Values["action"] = page.action;

    return pageResult;
}

如您所见,我从数据库中获取页面,因此站点管理员可以更改页面的路由(www.site.com/page -> www.site.com/other-name)并且站点可以正常工作使用新名称。

我在数据库中检索页面的文化,因为每个页面都可能具有不同的文化,例如,如果您访问 www.site.com/page 它会获取英文内容,而如果您访问 www. site.com/pagina 它以西班牙语显示内容。

当用户可以使用日期过滤页面时,除了一个细节之外,这很完美。

@using (Ajax.BeginForm(null, null, new AjaxOptions { HttpMethod = FormMethod.Get.ToString(), InsertionMode = InsertionMode.Replace, UpdateTargetId = "content_list", Url = Url.Action("UsersItems", "Users"), OnComplete = "OnComplete" }, new { id = "formSearch" }))
{
    ...
     @Html.DatePickerRangeFor(model => model.DateFrom, new { @class = "form-control", Value = Model.DateFrom == null ? "" : Convert.ToDateTime(Model.DateFrom).ToShortDateString()})
}

我必须使用自定义 ModelBinder 根据所选页面的语言将日期更改为正确的格式。

public class NullableDateTimeBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var cultureInfo = new CultureInfo(controllerContext.RouteData.Values["culture"].ToString());
        System.Threading.Thread.CurrentThread.CurrentUICulture = cultureInfo;
        System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name);

        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        return value?.ConvertTo(typeof(DateTime), CultureInfo.CurrentCulture);
    }
}

我的问题是

controllerContext.RouteData.Values["culture"]

始终为空。当我第一次加载页面时,RouteData 获取了文化,但是在执行部分 ajax 请求时,所有值都消失了,并且 ModelBinder 给了我一个错误。

我不想将当前文化存储在会话变量中,因为我从数据库页面读取语言并且我只遇到加载部分视图的 ajax 请求的问题。

有什么方法可以将当前页面的文化传递给 ModelBinder?

提前致谢。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-routing custom-routes custom-model-binder routedata


    【解决方案1】:

    与其在ModelBinder 中设置当前文化,不如为此使用IAuthorizationFilter。请注意,IActionFilters 运行 after ModelBinderIAuthorizationFilters 运行 before ModelBinder

    using System.Globalization;
    using System.Threading;
    using System.Web.Mvc;
    
    public class CultureFilter : IAuthorizationFilter
    {
        private readonly string defaultCulture;
    
        public CultureFilter(string defaultCulture)
        {
            this.defaultCulture = defaultCulture;
        }
    
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            var values = filterContext.RouteData.Values;
    
            string culture = (string)values["culture"] ?? this.defaultCulture;
    
            CultureInfo ci = new CultureInfo(culture);
    
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(ci.Name);
        }
    }
    

    您可以通过将过滤器注册为全局过滤器来全局设置过滤器。

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new CultureFilter(defaultCulture: "en"));
            filters.Add(new HandleErrorAttribute());
        }
    }
    

    由于它在ModelBinder 运行之前运行,因此无需更改ModelBinder 中的文化,因为它会从请求中获取环境文化。因此,您可以完全消除自定义 ModelBinder

    当我第一次加载页面时,RouteData 获取了文化,但是在执行部分 ajax 请求时,所有值都消失了

    这是因为每当有 AJAX 请求进入时,您都会跳过路由:

    if (httpContext.Request.IsAjaxRequest() || httpContext.Request.Url == null) return null;
    

    你应该去掉那条线。

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var page = FindPageFromDataBase(httpContext.Request.Url);
        if (page == null) return null;
    
        var pageResult = new RouteData(this, new MvcRouteHandler());
        pageResult.Values["culture"] = page.Culture;
        pageResult.Values["controller"] = page.controller;
        pageResult.Values["action"] = page.action;
    
        return pageResult;
    }
    

    还请注意,您可能会得到一个空值的文化,因为它没有在您的默认路由中设置。您应该为每条无法通过 URL 传递文化的路由设置默认文化,并为每条可以可以通过文化的路由省略默认文化(这使得 URL路线匹配所需的段)。

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            routes.Add(new RouteWeb());
    
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { culture = "en", controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
    

    相关:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-07
      • 2021-05-14
      • 1970-01-01
      • 1970-01-01
      • 2019-08-07
      • 2017-02-09
      • 1970-01-01
      • 2015-08-28
      相关资源
      最近更新 更多