栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

启动后更改MVC6的路由收集

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

启动后更改MVC6的路由收集

答案是没有合理的方法可以做到这一点,即使您找到一种方法也不是一个好习惯。

解决问题的方法不正确

基本上,过去的MVC版本的路由配置旨在像DI配置一样工作-
也就是说,您将所有内容放在组合根目录中,然后在运行时使用该配置。问题是您
可以 在运行时将对象推送到配置中(很多人这样做),这不是正确的方法。

现在,配置已由真正的DI容器替换,此方法将不再起作用。现在只能在应用程序启动时完成注册步骤。

正确的方法

超越

Route
类在过去的MVC版本中所做的工作来自定义路由的正确方法是继承Routebase或Route。

AspNetCore(以前称为MVC
6)具有类似的抽象,IRouter和INamedRouter扮演相同的角色。与其前身很像,

IRouter
只有两种方法可以实现。

namespace Microsoft.AspNet.Routing{    public interface IRouter    {        // Derives a virtual path (URL) from a list of route values        VirtualPathData GetVirtualPath(VirtualPathContext context);        // Populates route data (including route values) based on the        // request        Task RouteAsync(RouteContext context);    }}

在此接口中,您可以实现路由的2向性质-用于路由值的URL和用于URL的路由值。

一个例子:
CachedRoute<TPrimaryKey>

这是一个跟踪和缓存主键到URL的1-1映射的示例。它是通用的,我已经测试它工作的主键是否

int
还是
Guid

有一个必须插入的可插入部分,可以

ICachedRouteDataProvider
在其中实现对数据库的查询。您还需要提供控制器和操作,因此此路由足够通用,可以通过使用多个实例将多个数据库查询映射到多个操作方法。

using Microsoft.AspNetCore.Routing;using Microsoft.Extensions.Caching.Memory;using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Threading.Tasks;public class CachedRoute<TPrimaryKey> : IRouter{    private readonly string _controller;    private readonly string _action;    private readonly ICachedRouteDataProvider<TPrimaryKey> _dataProvider;    private readonly IMemoryCache _cache;    private readonly IRouter _target;    private readonly string _cacheKey;    private object _lock = new object();    public CachedRoute(        string controller,         string action,         ICachedRouteDataProvider<TPrimaryKey> dataProvider,         IMemoryCache cache,         IRouter target)    {        if (string.IsNullOrWhiteSpace(controller)) throw new ArgumentNullException("controller");        if (string.IsNullOrWhiteSpace(action)) throw new ArgumentNullException("action");        if (dataProvider == null) throw new ArgumentNullException("dataProvider");        if (cache == null) throw new ArgumentNullException("cache");        if (target == null) throw new ArgumentNullException("target");        _controller = controller;        _action = action;        _dataProvider = dataProvider;        _cache = cache;        _target = target;        // Set Defaults        CacheTimeoutInSeconds = 900;        _cacheKey = "__" + this.GetType().Name + "_GetPageList_" + _controller + "_" + _action;    }    public int CacheTimeoutInSeconds { get; set; }    public async Task RouteAsync(RouteContext context)    {        var requestPath = context.HttpContext.Request.Path.Value;        if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')        { // Trim the leading slash requestPath = requestPath.Substring(1);        }        // Get the page id that matches.        TPrimaryKey id;        //If this returns false, that means the URI did not match        if (!GetPageList().TryGetValue(requestPath, out id))        { return;        }        //Invoke MVC controller/action        var routeData = context.RouteData;        // TODO: You might want to use the page object (from the database) to        // get both the controller and action, and possibly even an area.        // Alternatively, you could create a route for each table and hard-pre        // this information.        routeData.Values["controller"] = _controller;        routeData.Values["action"] = _action;        // This will be the primary key of the database row.        // It might be an integer or a GUID.        routeData.Values["id"] = id;        await _target.RouteAsync(context);    }    public VirtualPathData GetVirtualPath(VirtualPathContext context)    {        VirtualPathData result = null;        string virtualPath;        if (TryFindMatch(GetPageList(), context.Values, out virtualPath))        { result = new VirtualPathData(this, virtualPath);        }        return result;    }    private bool TryFindMatch(IDictionary<string, TPrimaryKey> pages, IDictionary<string, object> values, out string virtualPath)    {        virtualPath = string.Empty;        TPrimaryKey id;        object idObj;        object controller;        object action;        if (!values.TryGetValue("id", out idObj))        { return false;        }        id = SafeConvert<TPrimaryKey>(idObj);        values.TryGetValue("controller", out controller);        values.TryGetValue("action", out action);        // The logic here should be the inverse of the logic in         // RouteAsync(). So, we match the same controller, action, and id.        // If we had additional route values there, we would take them all         // into consideration during this step.        if (action.Equals(_action) && controller.Equals(_controller))        { // The 'OrDefault' case returns the default value of the type you're  // iterating over. For value types, it will be a new instance of that type.  // Since KeyValuePair<TKey, TValue> is a value type (i.e. a struct),  // the 'OrDefault' case will not result in a null-reference exception.  // Since TKey here is string, the .Key of that new instance will be null. virtualPath = pages.FirstOrDefault(x => x.Value.Equals(id)).Key; if (!string.IsNullOrEmpty(virtualPath)) {     return true; }        }        return false;    }    private IDictionary<string, TPrimaryKey> GetPageList()    {        IDictionary<string, TPrimaryKey> pages;        if (!_cache.TryGetValue(_cacheKey, out pages))        { // only allow one thread to poplate the data lock (_lock) {     if (!_cache.TryGetValue(_cacheKey, out pages))     {         pages = _dataProvider.GetPageToIdMap();         _cache.Set(_cacheKey, pages,  new MemoryCacheEntryOptions()  {      Priority = CacheItemPriority.NeverRemove,      AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(this.CacheTimeoutInSeconds)  });     } }        }        return pages;    }    private static T SafeConvert<T>(object obj)    {        if (typeof(T).Equals(typeof(Guid)))        { if (obj.GetType() == typeof(string)) {     return (T)(object)new Guid(obj.ToString()); } return (T)(object)Guid.Empty;        }        return (T)Convert.ChangeType(obj, typeof(T));    }}

CmsCachedRouteDataProvider

这就是数据提供程序的实现,基本上是您需要在CMS中执行的操作。

public interface ICachedRouteDataProvider<TPrimaryKey>{    IDictionary<string, TPrimaryKey> GetPageToIdMap();}public class CmsCachedRouteDataProvider : ICachedRouteDataProvider<int>{    public IDictionary<string, int> GetPageToIdMap()    {        // Lookup the pages in DB        return (from page in DbContext.Pages     select new KeyValuePair<string, int>(         page.Url.TrimStart('/').TrimEnd('/'),         page.Id)     ).ToDictionary(pair => pair.Key, pair => pair.Value);    }}

用法

在这里,我们在默认路由之前添加路由,并配置其选项。

// Add MVC to the request pipeline.app.UseMvc(routes =>{    routes.Routes.Add(        new CachedRoute<int>( controller: "Cms", action: "Index", dataProvider: new CmsCachedRouteDataProvider(),  cache: routes.ServiceProvider.GetService<IMemoryCache>(),  target: routes.DefaultHandler)        { CacheTimeoutInSeconds = 900        });    routes.MapRoute(        name: "default",        template: "{controller=Home}/{action=Index}/{id?}");    // Uncomment the following line to add a route for porting Web API 2 controllers.    // routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");});

这就是要旨。您仍然可以改善一点。

例如,我个人将使用工厂模式并将存储库注入到构造器中,

CmsCachedRouteDataProvider
而不是
DbContext
在各处进行硬编码。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/432974.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号