एएसपी.नेट एमवीसी स्रोत कोड के माध्यम से घंटों के लिए सबसे अच्छा समाधान (मैं प्रत्येक नियंत्रक कार्रवाई के सिंक्रोनस संस्करणों को बनाने के अलावा) के साथ आने में सक्षम हूं, मैन्युअल रूप से एसिंक एक्शन के लिए एक्शन डिस्क्रिप्टर का आह्वान करना है Controller.HandleUnknownAction
के भीतर विधियां।
मैं इस कोड से विशेष रूप से खुश नहीं हूं और मुझे उम्मीद है कि इसे बेहतर किया जा सकता है, लेकिन यह काम करता है।
विचार जानबूझकर एक अमान्य कार्रवाई ("_" के साथ उपसर्ग) का अनुरोध करना है जो नियंत्रक पर HandleUnknownAction
विधि का आह्वान करेगा। यहां हम एक मिलान एसिंक एक्शन की तलाश करते हैं (पहले actionName
से अंडरस्कोर को हटाकर) और AsyncActionDescriptor.BeginExecute
विधि का आह्वान करें। EndExecute
विधि को तुरंत कॉल करके हम प्रभावी ढंग से एक्शन डिस्क्रिप्टर सिंक्रनाइज़ निष्पादित कर रहे हैं।
public ActionResult Index()
{
return View();
}
public async Task<ActionResult> Widget(int page = 10)
{
var content = await new HttpClient().GetStringAsync("http://www.foo.com")
.ConfigureAwait(false);
ViewBag.Page = page;
return View(model: content);
}
protected override void HandleUnknownAction(string actionName)
{
if (actionName.StartsWith("_"))
{
var asyncActionName = actionName.Substring(1, actionName.Length - 1);
RouteData.Values["action"] = asyncActionName;
var controllerDescriptor = new ReflectedAsyncControllerDescriptor(this.GetType());
var actionDescriptor = controllerDescriptor.FindAction(ControllerContext, asyncActionName)
as AsyncActionDescriptor;
if (actionDescriptor != null)
{
AsyncCallback endDelegate = delegate(IAsyncResult asyncResult)
{
};
IAsyncResult ar = actionDescriptor.BeginExecute(ControllerContext, RouteData.Values, endDelegate, null);
var actionResult = actionDescriptor.EndExecute(ar) as ActionResult;
if (actionResult != null)
{
actionResult.ExecuteResult(ControllerContext);
}
}
}
else
{
base.HandleUnknownAction(actionName);
}
}
दृश्य
<h2>Index</h2>
@Html.Action("_widget", new { page = 5 }) <!-- note the underscore prefix -->
मैं लगभग निश्चित है वहाँ Controller.BeginExecute
अधिभावी द्वारा एक बेहतर तरीका है हूँ। डिफ़ॉल्ट कार्यान्वयन नीचे देखा जा सकता है। विचार तुरंत Controller.EndExecuteCore
निष्पादित करना होगा हालांकि मुझे अब तक कोई सफलता नहीं मिली है।
protected virtual IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
{
if (DisableAsyncSupport)
{
// For backwards compat, we can disallow async support and just chain to the sync Execute() function.
Action action =() =>
{
Execute(requestContext);
};
return AsyncResultWrapper.BeginSynchronous(callback, state, action, _executeTag);
}
else
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
// Support Asynchronous behavior.
// Execute/ExecuteCore are no longer called.
VerifyExecuteCalledOnce();
Initialize(requestContext);
return AsyncResultWrapper.Begin(callback, state, BeginExecuteCore, EndExecuteCore, _executeTag);
}
}
स्रोत
2012-11-03 14:56:23
पहली बात यह है कि मन में आता है एक नया विस्तार विधि 'Html.ActionAsync' कि बस पाइपलाइन लागू करेगा की तरह आप चाहते हैं, लेकिन जोड़ने के लिए' सहायक विधि के अंत करने के लिए कॉल .Result' है शरीर, इस प्रकार आपके एसिंक कॉल को सिंक कॉल में बदल देता है। निश्चित रूप से दिलचस्प समस्या है। – Tejs
यह मैं था, मैं एक नया नियंत्रक बनाउंगा जो CreateActionInvoker या हैंडल अज्ञात एक्शन को ओवरराइड करता है और प्रतिबिंब के साथ एक सिंक्रोनस आमंत्रण करने के लिए एक लक्ष्य नियंत्रक को देखता है। आपको केवल नियंत्रक को एक बार लागू करना होगा और इसे किसी भी एसिंक एक्शन के लिए पुन: उपयोग करना होगा। –
@ टीजेएस हाँ यह विचार समाधान होगा हालांकि ढांचे का यह क्षेत्र बहुत असीमित अनुकूल नहीं है। समस्या 'HttpServerUtilityBase.Execute' के अंदर कहीं गहरी लगती है। @ थिकिंगसाइट्स - अधिक जानकारी के साथ उत्तर क्यों पोस्ट नहीं करें? यह एक अच्छा कामकाज की तरह लगता है। –