ASP.NET MVC 소스 코드를 몇 시간 추적 해 본 결과 (모든 컨트롤러 작업의 동기 버전 생성은 제외하고) 비동기 작업에 대한 작업 설명자를 수동으로 호출하는 것이 좋습니다. 방법은 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);
}
}
마음에 오는 첫번째 일은'헬퍼 방법의 끝에 전화 .Result' 당신이 원하는처럼 단순히 파이프 라인을 호출하는 새로운 확장 메서드 'Html.ActionAsync'를 만들지 만 추가하는 것입니다 따라서 비동기 호출을 동기화 호출로 변환 할 수 있습니다. 흥미로운 문제 야. – Tejs
이게 저 였나요? CreateActionInvoker 또는 HandleUnknownAction을 재정의하고 동기 호출을 수행 할 대상 컨트롤러를 반사 모양으로 새 컨트롤러를 만들겠습니다. 컨트롤러를 한 번만 구현해야하며 비동기 작업을 위해 컨트롤러를 다시 사용할 수 있습니다. –
@Tejs 네, 이것이 프레임 워크의이 영역이 비동기 적으로 친숙하지는 않지만 아이디어 솔루션이 될 것입니다. 문제가'HttpServerUtilityBase.Execute' 내부 깊숙한 곳에있는 것 같습니다. @ThikingSites - 자세한 내용을 게시하는 이유는 무엇입니까? 이것은 좋은 해결 방법처럼 들립니다. –