मैं एमवीसी 6 के साथ काम करने के लिए this sample RouteBase implementation को परिवर्तित करने का प्रयास कर रहा हूं। मैंने the example in the Routing project का पालन करके इसे अधिकतर काम किया है, लेकिन मैं वापस कैसे लौटने के लिए आगे बढ़ रहा हूं विधि से एसिंक्रोनस Task
। मुझे वास्तव में परवाह नहीं है कि यह वास्तव में असीमित है (किसी को भी उत्साहित करता है जो उस उत्तर को प्रदान कर सकता है), क्योंकि अब मैं इसे काम करना चाहता हूं।एएसपी.NET 5 (vNext) में एक कस्टम आईरौटर को लागू करना एमवीसी 6
मेरे पास आउटगोइंग मार्ग कार्यरत हैं (जिसका मतलब है कि ActionLink
मार्ग मानों में डालते समय ठीक काम करता है)। समस्या RouteAsync
विधि के साथ है।
public 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 that matches.
var page = GetPageList()
.Where(x => x.VirtualPath.Equals(requestPath))
.FirstOrDefault();
// If we got back a null value set, that means the URI did not match
if (page != null)
{
var routeData = new RouteData();
// This doesn't work
//var routeData = new RouteData(context.RouteData);
// This doesn't work
//routeData.Routers.Add(this);
// This doesn't work
//routeData.Routers.Add(new MvcRouteHandler());
// 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-code
// this information.
routeData.Values["controller"] = "CustomPage";
routeData.Values["action"] = "Details";
// This will be the primary key of the database row.
// It might be an integer or a GUID.
routeData.Values["id"] = page.Id;
context.RouteData = routeData;
// When there is a match, the code executes to here
context.IsHandled = true;
// This test works
//await context.HttpContext.Response.WriteAsync("Hello there");
// This doesn't work
//return Task.FromResult(routeData);
// This doesn't work
//return Task.FromResult(context);
}
// This satisfies the return statement, but
// I'm not sure it is the right thing to return.
return Task.FromResult(0);
}
पूरी विधि एक मैच होने पर अंत तक सभी तरह से चलती है। लेकिन जब इसे निष्पादित किया जाता है, तो यह CustomPage
नियंत्रक की Details
विधि को कॉल नहीं करता है, जैसा कि इसे करना चाहिए। मुझे बस ब्राउज़र में एक खाली सफेद पृष्ठ मिलता है।
मैं के रूप में this post में किया गया था और यह खाली पृष्ठ पर Hello there
लिखते हैं WriteAsync
लाइन जोड़ा है, लेकिन मैं नहीं समझ सकता क्यों MVC मेरी नियंत्रक बुला नहीं है (पिछले संस्करणों इस बिना किसी बाधा के काम में)। दुर्भाग्यवश, उस पोस्ट को IRouter
या INamedRouter
को कार्यान्वित करने के तरीके को छोड़कर रूटिंग के प्रत्येक भाग को शामिल किया गया।
मैं RouteAsync
विधि फ़ंक्शन कैसे बना सकता हूं?
पूरे CustomRoute कार्यान्वयन
using Microsoft.AspNet.Routing;
using Microsoft.Framework.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public class PageInfo
{
// VirtualPath should not have a leading slash
// example: events/conventions/mycon
public string VirtualPath { get; set; }
public int Id { get; set; }
}
public interface ICustomRoute : IRouter
{ }
public class CustomRoute : ICustomRoute
{
private readonly IMemoryCache cache;
private object synclock = new object();
public CustomRoute(IMemoryCache cache)
{
this.cache = cache;
}
public 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 that matches.
var page = GetPageList()
.Where(x => x.VirtualPath.Equals(requestPath))
.FirstOrDefault();
// If we got back a null value set, that means the URI did not match
if (page != null)
{
var routeData = new 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-code
// this information.
routeData.Values["controller"] = "CustomPage";
routeData.Values["action"] = "Details";
// This will be the primary key of the database row.
// It might be an integer or a GUID.
routeData.Values["id"] = page.Id;
context.RouteData = routeData;
context.IsHandled = true;
}
return Task.FromResult(0);
}
public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
VirtualPathData result = null;
PageInfo page = null;
// Get all of the pages from the cache.
var pages = GetPageList();
if (TryFindMatch(pages, context.Values, out page))
{
result = new VirtualPathData(this, page.VirtualPath);
context.IsBound = true;
}
return result;
}
private bool TryFindMatch(IEnumerable<PageInfo> pages, IDictionary<string, object> values, out PageInfo page)
{
page = null;
int id;
object idObj;
object controller;
object action;
if (!values.TryGetValue("id", out idObj))
{
return false;
}
id = Convert.ToInt32(idObj);
values.TryGetValue("controller", out controller);
values.TryGetValue("action", out action);
// The logic here should be the inverse of the logic in
// GetRouteData(). 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("Details") && controller.Equals("CustomPage"))
{
page = pages
.Where(x => x.Id.Equals(id))
.FirstOrDefault();
if (page != null)
{
return true;
}
}
return false;
}
private IEnumerable<PageInfo> GetPageList()
{
string key = "__CustomPageList";
IEnumerable<PageInfo> pages;
// Only allow one thread to poplate the data
if (!this.cache.TryGetValue(key, out pages))
{
lock (synclock)
{
if (!this.cache.TryGetValue(key, out pages))
{
// TODO: Retrieve the list of PageInfo objects from the database here.
pages = new List<PageInfo>()
{
new PageInfo() { Id = 1, VirtualPath = "somecategory/somesubcategory/content1" },
new PageInfo() { Id = 2, VirtualPath = "somecategory/somesubcategory/content2" },
new PageInfo() { Id = 3, VirtualPath = "somecategory/somesubcategory/content3" }
};
this.cache.Set(key, pages,
new MemoryCacheEntryOptions()
{
Priority = CacheItemPriority.NeverRemove,
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15)
});
}
}
}
return pages;
}
}
CustomRoute डि पंजीकरण
services.AddTransient<ICustomRoute, CustomRoute>();
MVC मार्ग विन्यास
// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
routes.Routes.Add(routes.ServiceProvider.GetService<ICustomRoute>());
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?}");
});
मामले में यह मायने रखती है मैं Beta 5
, DNX 4.5.1
और DNX Core 5
उपयोग कर रहा हूँ।
समाधान
मैं एक सामान्य समाधान है कि जानकारी मैं यहाँ सीखा के आधार पर यूआरएल 2 तरह मानचित्रण in this answer के लिए एक सरल प्राथमिक कुंजी के लिए इस्तेमाल किया जा सकता बनाया। प्राथमिक कुंजी के नियंत्रक, क्रिया, डेटा प्रदाता, और डेटाटाइप को एमवीसी 6 रूटिंग में तारों के दौरान निर्दिष्ट किया जा सकता है।
हाँ मैंने एक आंतरिक आईरौटर होने के बारे में सोचा था, लेकिन मुझे नहीं लगता कि आपको इसकी आवश्यकता है। संदर्भ स्थापित करना। इसे झूठ बोलने और जल्दी लौटने से यह अगले पंजीकृत आईरौटर में स्थानांतरित हो जाएगा और आखिरकार मार्गों पर फॉलबैक होगा। डिफॉल्ट हैंडलर (जो एमवीआर रूट हंडलर है) – Dealdiane
क्या आप सुनिश्चित हैं कि कोई रूट नहीं होने पर डिफॉल्ट हैंडलर का उपयोग किया जाएगा ? ऐसा लगता है कि कोड का उपयोग केवल ['MapRoute'] (https://github.com/aspnet/Routing/blob/dev/src/Microsoft.AspNet.Routing/RouteBuilderExtensions.cs) एक्सटेंशन विधि के लिए किया जा रहा है, इसलिए एमवीसी मार्गों को टेम्पलेट रूट का उपयोग एक आंतरिक एमवीसी रूटआउट हैंडलर –
के साथ जोड़ा जाता है ['रूटबिल्डर.बिल्ड'] भी देखें (https://github.com/aspnet/Routing/blob/dev/src/Microsoft.AspNet.Routing/RouteBuilder.cs) जो प्रत्येक परिभाषित मार्गों को जोड़ देगा, लेकिन डिफ़ॉल्ट हैंडलर –