簡體   English   中英

異步 MVC 控制器和 HttpTaskAsyncHandler

[英]Asynchronous MVC controller and HttpTaskAsyncHandler

我正在嘗試為我的自定義內容管理解決方案實現自定義HttpTaskAsyncHandler 這個想法是將/100/my-little-pony路由到/Details/my-little-pony 我希望通過以下HttpTaskAsyncHandler實現這一點

public override async Task ProcessRequestAsync(HttpContext context)
{
    try
    {
        var id = GetContentIdFromRouteData();

        // Retrieve the content identified by the specified ID
        var contentRepository = new ContentRepository();
        var content = await contentRepository.GetAsync(id);

        if (content == null)
            throw new ContentNotFoundException(id);

        // Initialize an instance of the content controller
        var factory = ControllerBuilder.Current.GetControllerFactory();
        var controller = (IContentController) factory.CreateController(_requestContext, content.ControllerName);
        if (controller == null)
            throw new ControllerNotFoundException(content.ControllerName);

        try
        {
            // Retrieve all content type values and pass them on the the method for index pages
            var action = _requestContext.RouteData.GetRequiredString("action");
            if (action == "Index")
            {
                ContentType data = null;
                if (controller.ContentType != null)
                {
                    data = BusinessHost.Resolve<ContentType>(controller.ContentType);
                    data.Values = content.Parameters.ToDictionary(p => p.Name, p => p.Value);
                }
                _requestContext.RouteData.Values.Add("data", data);
            }

            var values = _requestContext.RouteData.Values;
            values.Add("name", content.Name);
            values.Add("controllerId", id);
            values.Add("controller", content.ControllerName);

            controller.Execute(_requestContext);
        }
        finally
        {
            factory.ReleaseController(controller);
        }
    }
    catch (ContentNotFoundException ex)
    {
        Trace.TraceWarning($"404: {ex.Message}");
        _requestContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
    }
}

這對於同步請求非常有效,但是當我嘗試調用異步方法時......

@using (Html.BeginForm("Save", Html.ControllerId(), FormMethod.Post, new { @class = "form-horizontal" }))

......這就是方法......

[HttpPost]
public async Task<ActionResult> Save(NewsViewModel model)
{ }

編輯我已將方法名稱更改為Save as Async is not inferred,我收到一個新錯誤:

異步操作方法“登錄”返回一個無法同步執行的任務。

操作名稱是SaveAsync ,但引用它的代碼使用Save作為名稱。 任何操作都沒有神奇的重命名,包括異步一次。

您的選擇:

  • 使用SaveAsync來引用動作
  • 使用ActionName屬性重命名動作
  • 將方法重命名為Save (但這違反了所有async方法都具有...Async后綴的約定)

旁注:與某些自定義處理程序相比,使用路由可能是更好的重定向選擇。

MvcHandler 的功能遠不止眼前所見,我已經意識到人們不能簡單地希望憑良心復制它。 因此,我決定完全改變我處理這個問題的方式:我沒有嘗試實現我自己的MvcHandler ,而是擴展了我的IRouteHandler

這是我的解決方案:

private static ConcurrentDictionary<string, Type> _contentTypes = new ConcurrentDictionary<string, Type>();

public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
    // Retrieve the page ID from the route data
    var id = GetContentIdFromRouteData(requestContext);

    // Retrieve the content identified by the specified ID
    var contentRepository = new ContentRepository();
    var content = contentRepository.Get(id);

    if (content == null)
        throw new ContentNotFoundException(id);

    // Retrieve all content type values and pass them on the the method for index pages
    var action = requestContext.RouteData.GetRequiredString("action");
    if (action == "Index")
    {
        var data = CreateContentType(requestContext, content);
        requestContext.RouteData.Values.Add("data", data);
    }

    var values = requestContext.RouteData.Values;
    values.Add("name", content.Name);
    values.Add("controllerId", id);
    values.Add("controller", content.ControllerName);

    return new MvcHandler(requestContext);
}

private static int GetContentIdFromRouteData(RequestContext context)
{
    var idString = context.RouteData.GetRequiredString("id");
    int id;

    if (!int.TryParse(idString, out id))
        throw new ArgumentException("Content can't be loaded due to an invalid route parameter.", "id");

    return id;
}

private static ContentType CreateContentType(RequestContext context, Content content)
{
    Type type;
    if (!_contentTypes.ContainsKey(content.ControllerName) || 
        !_contentTypes.TryGetValue(content.ControllerName, out type))
    {
        var factory = ControllerBuilder.Current.GetControllerFactory();
        var controller = (IContentController)factory.CreateController(context, content.ControllerName);

        if (controller == null)
            throw new ControllerNotFoundException(content.ControllerName);

        type = controller.ContentType;
        factory.ReleaseController(controller);

        _contentTypes.TryAdd(content.ControllerName, type);                
    }

    ContentType data = null;
    if (type != null)
    {
        data = BusinessHost.Resolve<ContentType>(type);
        data.Values = content.Parameters.ToDictionary(p => p.Name, p => p.Value);
    }

    return data;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM