this sample RouteBase implementationをMVC 6で使用するように変換しようとしています。私はそのほとんどをthe example in the Routing projectに従っていますが、復帰方法が遅れていますこのメソッドの非同期Task
私は実際に非同期であるかどうかは気にしません(その答えを提供できる人に歓声をあげます)。今は機能したいだけです。ASP.NET 5(vNext)MVC 6でカスタムIRouterを実装する
私は、ルートが機能しています(ルート値を入力すると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
を書き込みますが、MVCは(以前のバージョンでは、これが滞りなく働いていた)私のコントローラを呼び出していない理由を私は理解できないたように私はWriteAsync
行を追加しました。残念ながら、その投稿は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 DI登録
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
を使用しています重要な場合。
ソリューションは、私がここで学習した情報に基づいてURL 2ウェイマッピングin this answerへの単純な主キーのために使用することができる汎用的なソリューションを作成しました。主キーのコントローラ、アクション、データプロバイダ、およびデータ型は、MVC 6ルーティングに配線するときに指定できます。
ええ、私も内部のIRouterを持っていることを考えましたが、私はあなたがそれを必要とは思わない。 context.IsHandledをfalseに設定して早期に戻すと、次に登録されたIRouterに移動し、最終的にroutes.DefaultHandler(これはMvcRouteHandler)にフォールバックします。 – Dealdiane
一致するルートがない場合はDefaultHandlerが使用されますか?コードを見ると、['MapRoute'](https://github.com/aspnet/Routing/blob/dev/src/Microsoft.AspNet.Routing/RouteBuilderExtensions.cs)拡張メソッドのためだけに使用されているようですMVCルートは、内部MvcRouteHandlerを持つTemplateRouteを使用して追加されます –
['RouteBuilder.Build'](https://github.com/aspnet/Routing/blob/dev/src/Microsoft.AspNet.Routing/RouteBuilder.cs)もチェックしてください。定義済みの各ルートを追加するだけですが、デフォルトのハンドラは追加されません –