Imlementing eine Benutzerdefinierte IRouter in ASP.NET 5 (vNext) MVC 6

Ich bin versucht zu konvertieren dieses Beispiel RouteBase Umsetzung arbeiten mit MVC-6. Ich habe die meisten davon durch den folgenden das Beispiel in der Routing-Projekt, aber ich bin immer stolperte auf wie die Rückkehr der asynchronen Task von der Methode. Ich weiß wirklich nicht egal, ob es sich tatsächlich asynchron ist (prost, wer kann vorsehen, dass Antwort), für jetzt möchte ich nur, es funktioniert.

Habe ich die ausgehenden Strecken funktionieren (also ActionLink funktioniert gut, wenn ich in der route-Werten). Das problem ist mit der RouteAsync Methode.

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);
}

Die gesamte Methode läuft den ganzen Weg durch bis zum Ende, wenn es eine übereinstimmung gibt. Aber wenn es fertig ist die Ausführung, es nicht an die Details Methode der CustomPage controller, wie es sein sollte. Bekomme ich nur eine leere weiße Seite im browser.

Habe ich den WriteAsync Linie wie in dieser Beitrag und es schreibt Hello there auf die leere Seite, aber ich kann nicht verstehen, warum MVC nicht anrufen, mein controller (in früheren Versionen klappte dies ohne Probleme). Leider, dass die post unter jedem Teil der routing-außer implementieren Sie eine IRouter oder INamedRouter.

Wie kann ich machen das RouteAsync Methode Funktion?

Gesamte CustomRoute Umsetzung

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-Registrierung

services.AddTransient<ICustomRoute, CustomRoute>();

MVC-Route-Konfiguration

//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?}");
});

Falls es wichtig ist ich bin mit Beta 5, DNX 4.5.1 und DNX Core 5.

Lösung

Erstellte ich eine generische Lösung, die verwendet werden kann für einen einfachen Primärschlüssel URL 2-Wege-mapping in dieser Antwort auf der Grundlage der Informationen, die ich hier gelernt. Der controller, action, data provider und dem Datentyp des Primärschlüssels angegeben werden können, wenn die Verkabelung es in MVC-6-routing.

InformationsquelleAutor NightOwl888 | 2015-09-15
Schreibe einen Kommentar