2014-11-13 9 views
23

में एमवीसी 6 में @Html.Action कहां है? मैं @Html.ActionLink देख सकता हूं लेकिन पहले की तरह किसी एक्शन को प्रत्यक्ष कॉल नहीं कर सकता।@ एचटीएमएल। Asp.Net कोर

क्या इसे ViewComponents द्वारा प्रतिस्थापित किया गया था?

उत्तर

1

नेट कोर के लिए 2,0

using Microsoft.AspNetCore.Mvc.Infrastructure; 

// var actionSelector = GetServiceOrFail<IActionSelectorDecisionTreeProvider>(currentHttpContext); 
var actionSelector = GetServiceOrFail<IActionDescriptorCollectionProvider>(currentHttpContext); 

और

// var actionDescriptor = actionSelector.DecisionTree.Select(routeValues).First(); 
var actionDescriptor = actionSelector.ActionDescriptors.Items.Where(i => i.RouteValues["Controller"] == controller && i.RouteValues["Action"] == action).First(); 
+3

मैं इस बदलाव को कहां से स्पष्ट नहीं कर रहा हूं? क्या आप उस जानकारी को उन लोगों के उत्तर में जोड़ सकते हैं जो दिमाग नहीं पढ़ सकते हैं? –

+0

मुझे विश्वास है कि यह कस्टम @ Html.RenderAction कार्यान्वयन के लिए नीचे है। – Engin

20

हाँ, ViewComponents ऐसा करने का नया तरीका हो सकता है, लेकिन वे बिल्कुल @Html.Action क्या कर रहा था के रूप में ही नहीं हैं इससे पहले कि हालांकि ... उदाहरण के लिए, MVC5 और पूर्व, लागू 'बच्चे कार्यों' में भी होगा किसी भी फ़िल्टर को निष्पादित करें (उदाहरण के लिए, यदि नियंत्रक को उन पर सजाए गए फ़िल्टर होते हैं) उन्हें नियमित क्रियाओं के रूप में दिखाते हैं ... लेकिन यह ViewComponents के साथ सच नहीं है और उन्हें वास्तविक अनुरोध के संदर्भ में निष्पादित किया जाता है ...

दृश्य घटकों पर अधिक जानकारी: http://www.asp.net/vnext/overview/aspnet-vnext/vc#intro

अपडेट: लिंक बदल दिया गया है

https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components

+0

उत्कृष्ट। अब हम "आंशिक विचार" (अब ViewComponents) का आविष्कार करते समय एसिंक्रोनस कॉल का उपयोग कर सकते हैं –

10

ViewComponents महान, लेकिन नहीं अजाक्स के लिए इतना बड़ा कर रहे हैं।

यदि आप वास्तव में @ Html.RenderAction विधि को याद करते हैं, तो यहां एक त्वरित कार्यान्वयन है जिसे मैंने AspNetCore के लिए एक साथ फेंक दिया है।

using System; 
using System.IO; 
using System.Linq; 
using System.Threading.Tasks; 
using Microsoft.AspNetCore.Html; 
using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Http.Extensions; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.AspNetCore.Mvc.Controllers; 
using Microsoft.AspNetCore.Mvc.Internal; 
using Microsoft.AspNetCore.Mvc.Infrastructure; 
using Microsoft.AspNetCore.Mvc.Razor; 
using Microsoft.AspNetCore.Mvc.Rendering; 
using Microsoft.AspNetCore.Routing; 

namespace Microsoft.AspNetCore.Mvc.Rendering { 

    public static class HtmlHelperViewExtensions 
    { 

     public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, object parameters = null) 
     { 
      var controller = (string)helper.ViewContext.RouteData.Values["controller"]; 

      return RenderAction(helper, action, controller, parameters); 
     } 

     public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, string controller, object parameters = null) 
     { 
      var area = (string)helper.ViewContext.RouteData.Values["area"]; 

      return RenderAction(helper, action, controller, area, parameters); 
     } 

     public static IHtmlContent RenderAction(this IHtmlHelper helper, string action, string controller, string area, object parameters = null) 
     { 
      if (action == null) 
       throw new ArgumentNullException("action"); 

      if (controller == null) 
       throw new ArgumentNullException("controller"); 

      if (area == null) 
       throw new ArgumentNullException("area"); 

      var task = RenderActionAsync(helper, action, controller, area, parameters); 

      return task.Result; 
     } 

     private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null) 
     { 
      // fetching required services for invocation 
      var currentHttpContext = helper.ViewContext?.HttpContext; 
      var httpContextFactory = GetServiceOrFail<IHttpContextFactory>(currentHttpContext); 
      var actionInvokerFactory = GetServiceOrFail<IActionInvokerFactory>(currentHttpContext); 
      var actionSelector = GetServiceOrFail<IActionSelectorDecisionTreeProvider>(currentHttpContext); 

      // creating new action invocation context 
      var routeData = new RouteData(); 
      var routeParams = new RouteValueDictionary(parameters ?? new { }); 
      var routeValues = new RouteValueDictionary(new { area = area, controller = controller, action = action }); 
      var newHttpContext = httpContextFactory.Create(currentHttpContext.Features); 

      newHttpContext.Response.Body = new MemoryStream(); 

      foreach (var router in helper.ViewContext.RouteData.Routers) 
       routeData.PushState(router, null, null); 

      routeData.PushState(null, routeValues, null); 
      routeData.PushState(null, routeParams, null); 

      var actionDescriptor = actionSelector.DecisionTree.Select(routeValues).First(); 
      var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor); 

      // invoke action and retreive the response body 
      var invoker = actionInvokerFactory.CreateInvoker(actionContext); 
      string content = null; 

      await invoker.InvokeAsync().ContinueWith(task => { 
       if (task.IsFaulted) 
       { 
        content = task.Exception.Message; 
       } 
       else if (task.IsCompleted) 
       { 
        newHttpContext.Response.Body.Position = 0; 
        using (var reader = new StreamReader(newHttpContext.Response.Body)) 
         content = reader.ReadToEnd(); 
       } 
      }); 

      return new HtmlString(content); 
     } 

     private static TService GetServiceOrFail<TService>(HttpContext httpContext) 
     { 
      if (httpContext == null) 
       throw new ArgumentNullException(nameof(httpContext)); 

      var service = httpContext.RequestServices.GetService(typeof(TService)); 

      if (service == null) 
       throw new InvalidOperationException($"Could not locate service: {nameof(TService)}"); 

      return (TService)service; 
     } 
    } 
} 

आप अपने दृश्य से इन तरीकों में से एक का उपयोग कर आह्वान कर सकते हैं:

@Html.RenderAction("action", "controller", "area", new { id = 1}) 
@Html.RenderAction("action", "controller", new { id = 1}) 
@Html.RenderAction("action", new { id = 1}) 

नोट:

नियंत्रक नाम, और वैकल्पिक क्षेत्र का नाम, ActionContext अगर से संबंधित मानों लागू हो जाएगी नहीं दिया गया।

+0

तकनीकी रूप से, यह कोड Html.Action() के लिए एक प्रतिस्थापन है, जो एक स्ट्रिंग मान के रूप में कार्य देता है। एचटीएमएल। रेंडरएक्शन() सीधे प्रतिक्रिया स्ट्रीम पर कार्रवाई लिखता है, और शून्य लौटाता है। – ReflexiveCode

+0

मैंने इस कोड का उपयोग करने का प्रयास किया है, लेकिन जब मैं एक से अधिक बार Html.RenderAction को कॉल करता हूं तो मुझे एक त्रुटि मिलती है, "एक या अधिक त्रुटियां हुईं। (एक ही कुंजी वाला एक आइटम पहले से ही जोड़ा जा चुका है। कुंजी: System.Object) "। यह ControllerActionInvoker.Next में होता है जो अंत में "System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException" क्या आपको पता है क्या वस्तु एक प्रमुख के रूप में इस्तेमाल किया जाता है और कैसे मैं एक ही अनुरोध में कई उपयोगों के लिए अनुमति देने के लिए कोड को बदल सकता है है में समाप्त होता है ? –

+0

वही त्रुटि होने और इसे हल करने :(एक तरह से नहीं मिल सकता है एक या अधिक त्रुटियां हुईं।। (एक ही कुंजी के साथ एक आइटम पहले से ही जोड़ दिया गया है कुंजी:। System.Object)। – brechtvhb

1

हेल्पर एक्सटेंशन के लिए मेष द्वारा वर्कअराउंड नेट कोर 2.0 के लिए और अधिक व्यावहारिक नहीं है क्योंकि IActionSelectorDecisionTreeProvider को नए संस्करण से हटा दिया गया है। नीचे दिए गए लिंक को देखें।

https://github.com/Microsoft/aspnet-api-versioning/issues/154

2

की जगह asp.net कोर के लिए 2

using Microsoft.AspNetCore.Html; 
using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Mvc.Infrastructure; 
using Microsoft.AspNetCore.Routing; 
using Microsoft.Extensions.DependencyInjection; 
using System; 
using System.IO; 
using System.Threading.Tasks; 

namespace Microsoft.AspNetCore.Mvc.Rendering 
{ 
    public static class HtmlHelperViewExtensions 
    { 
     public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null) 
     { 
      var controller = (string)helper.ViewContext.RouteData.Values["controller"]; 

      return Action(helper, action, controller, parameters); 
     } 

     public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null) 
     { 
      var area = (string)helper.ViewContext.RouteData.Values["area"]; 

      return Action(helper, action, controller, area, parameters); 
     } 

     public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null) 
     { 
      if (action == null) 
       throw new ArgumentNullException("action"); 

      if (controller == null) 
       throw new ArgumentNullException("controller"); 


      var task = RenderActionAsync(helper, action, controller, area, parameters); 

      return task.Result; 
     } 

     private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null) 
     { 
      // fetching required services for invocation 
      var serviceProvider = helper.ViewContext.HttpContext.RequestServices; 
      var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>(); 
      var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>(); 
      var actionSelector = serviceProvider.GetRequiredService<IActionSelector>(); 

      // creating new action invocation context 
      var routeData = new RouteData(); 
      foreach (var router in helper.ViewContext.RouteData.Routers) 
      { 
       routeData.PushState(router, null, null); 
      } 
      routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null); 
      routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null); 

      //get the actiondescriptor 
      RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData }; 
      var candidates = actionSelector.SelectCandidates(routeContext); 
      var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates); 

      var originalActionContext = actionContextAccessor.ActionContext; 
      var originalhttpContext = httpContextAccessor.HttpContext; 
      try 
      { 
       var newHttpContext = serviceProvider.GetRequiredService<IHttpContextFactory>().Create(helper.ViewContext.HttpContext.Features); 
       if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper))) 
       { 
        newHttpContext.Items.Remove(typeof(IUrlHelper)); 
       } 
       newHttpContext.Response.Body = new MemoryStream(); 
       var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor); 
       actionContextAccessor.ActionContext = actionContext; 
       var invoker = serviceProvider.GetRequiredService<IActionInvokerFactory>().CreateInvoker(actionContext); 
       await invoker.InvokeAsync(); 
       newHttpContext.Response.Body.Position = 0; 
       using (var reader = new StreamReader(newHttpContext.Response.Body)) 
       { 
        return new HtmlString(reader.ReadToEnd()); 
       } 
      } 
      catch (Exception ex) 
      { 
       return new HtmlString(ex.Message); 
      } 
      finally 
      { 
       actionContextAccessor.ActionContext = originalActionContext; 
       httpContextAccessor.HttpContext = originalhttpContext; 
       if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper))) 
       { 
        helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper)); 
       } 
      } 
     } 
    } 
} 

यह मेष प्रतिक्रिया पर आधारित है। मैंने 2.0 के लिए संकलन नहीं किया था और मैंने कुछ बदलाव जोड़े। वर्तमान httpcontext और वर्तमान actioncontext के लिए 2 गौरवशाली स्थैतिक मान हैं। Httpcontext के लिए एक IHttpContextFactory.Create में सेट है और मैंने कोड में actioncontext के लिए एक सेट किया है।

एचटीपीकॉन्टेक्स्ट HttpContext.Features के आसपास सिर्फ एक रैपर है, इसलिए यदि आप किसी एक में कुछ बदलते हैं, तो यह दूसरे में भी बदल जाता है ... मैं कोशिश करता हूं कि मैं कोशिश/पकड़ के अंत में क्या जानता हूं।

मैंने आइटम कैश से IUrlHelper हटा दिया क्योंकि इस मान का पुन: उपयोग किया जाएगा भले ही क्रिया कॉन्टेक्स्ट urlHelper बनाने के लिए अलग है (IUrlHelperFactory.GetUrlHelper)।

एएसपीनेट कोर 2.0 मानता है कि आप ऐसा नहीं करेंगे, वहां एक अच्छा मौका है कि अन्य कैश किए गए चीजें हैं, इसलिए मैं इसका उपयोग करते समय सावधान रहने की सलाह देता हूं और अगर आपको इसकी आवश्यकता नहीं है तो बस नहीं।