asp.net mvc 特性 使用异步Controllers

使用asp.net异步执行请求的原因和好处,可以搜之,不赘叙。

看一个同步抓取网页图片的方法:

Public  ContentResult GetPhotoByTag(string tag)

{

    // Make a request to Flickr

    string url = string.Format(FlickrSearchApi, HttpUtility.UrlEncode(tag));

    using (var response = WebRequest.Create(url).GetResponse()) 

    {

        // Parse the response as XML

        Var xmlDoc = XDocument.Load(XmlReader.Create(response.GetResponseStream()));

        // Use LINQ to convert each <photo /> node to a URL string

        var photoUrls = from photoNode in xmlDoc.Descendants("photo")

                        select string.Format(

                            "http://farm{0}.static.flickr.com/{1}/{2}_{3}.jpg",

                            photoNode.Attribute("farm").Value,

                            photoNode.Attribute("server").Value,

                            photoNode.Attribute("id").Value,

                            photoNode.Attribute("secret").Value);

        // Return an <img> tag referencing the first photo

        return Content(string.Format("<img src='{0}'/>", photoUrls.First()));

    }

}

改写成异步。

实现异步Controller  3个关键点:

1,继承自AsyncController

2,方法名称格式:ActionNameAsync, ActionNameCompleted。

3,设置信号量

public class ImageController : AsyncController

{

    public void GetPhotoByTagAsync(string tag)

{

    AsyncManager.OutstandingOperations.Increment();

    // Begin an asynchronous request to Flickr

    string url = string.Format(FlickrSearchApi, HttpUtility.UrlEncode(tag));

    WebRequest request = WebRequest.Create(url);

    request.BeginGetResponse(asyncResult =>

    {

        // This lambda method will be executed when we've got a response from Flickr

        using (WebResponse response = request.EndGetResponse(asyncResult)) 

        {

           // Parse response as XML, then convert to each <photo> node to a URL

           var xml = XDocument.Load(XmlReader.Create(response.GetResponseStream()));

           var photoUrls = from photoNode in xml.Descendants("photo")

                           select string.Format(

                               "http://farm{0}.static.flickr.com/{1}/{2}_{3}.jpg",

                               photoNode.Attribute("farm").Value,

                               photoNode.Attribute("server").Value,

                               photoNode.Attribute("id").Value,

                               photoNode.Attribute("secret").Value);

           AsyncManager.Parameters["photoUrls"] = photoUrls;

           // Now allow the Completed method to run

           AsyncManager.OutstandingOperations.Decrement();

        }

    }, null);

}

public ContentResult GetPhotoByTagCompleted(IEnumerable<string> photoUrls)

{

    return Content(string.Format("<img src='{0}'/>", photoUrls.First()));

}

}

使用异步三部曲:1,方法名称:XXXXXAsync,XXXXXCompleted;2,一步方法中通过信号量控制同步:逻辑开始前递增信号量AsyncManager.OutstandingOperations.Increment();逻辑后递减信号量 AsyncManager.OutstandingOperations.Decrement();3,传参数和执行结果: AsyncManager.Parameters["photoUrls"] = photoUrls;

如何给completed传参数:

public void GetPhotoByTagAsync(string tag, string someOtherParam)

{

    AsyncManager.Parameters["someOtherParam"] = someOtherParam;

    // ... all else as before ...

}

public ContentResult GetPhotoByTagCompleted(IEnumerable<string> photoUrls, 

                                             string someOtherParam)

{

    // ...

}

通过AsyncManager.Parameters集合传键值对参数,Completed方法会试图通过参数名称去匹配参数值。

如何指定超时:

[AsyncTimeout(10000)]  // 10000 milliseconds equals 10 seconds

public void GetPhotoByTagAsync(string tag) { ... }

如何终止异步操作。

这里提供的方法比较粗暴,只能用AsyncManager.Finish()把所有未完成异步调用终止。该方法导致Completed提早调用,AsyncManager.Parameters里面的值会设置为默认值(0,null..etc)。

使用Sync() 强制回调方法运行在绑定了原始 HTTPContext的asp.net工作线程上:

在control中,假如异步方法带有回调,那么该回调将不可预见在什么线程上执行。自然不能肯定的去访问HTTPContext。解决办法是使用AsyncManager.Sync。示例:

BeginAsyncOperation (asyncResult => {

    var result = End (asyncResult);

    // Can't always access System.Web.HttpContext.Current from here...

    Action doSomethingWithHttpContext = () => {

        // ... but can always access it from this delegate

    };

    if (asyncResult.CompletedSynchronously) // Already on an ASP.NET thread

        doSomethingWithHttpContext();

    else                                    // Must switch to an ASP.NET thread

        AsyncManager.Sync(doSomethingWithHttpContext);

    AsyncManager.OutstandingOperations.Decrement();

}, null);

posted on 2011-03-07 23:49  arg  阅读(1278)  评论(0编辑  收藏  举报

导航