csharp Azure WebRole的WebAPI控制器,可以管理需要很长时间才能完成的请求。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了csharp Azure WebRole的WebAPI控制器,可以管理需要很长时间才能完成的请求。相关的知识,希望对你有一定的参考价值。

namespace WorkerRole
{
    public class WorkerRole : RoleEntryPoint
    {
        private readonly IMyResponseQueue responseQueue;

        private readonly ICache cache;

        public WorkerRole(ICache cache, IMyResponseQueue responseQueue)
        {
            this.cache = cache;
            this.responseQueue = responseQueue;
        }

        public override void Run()
        {
            this.responseQueue.Client.OnMessageAsync(
                async msg =>
                    {
                        this.ProcessMessage(msg);
                    });
        }

        private async Task ProcessMessage(BrokeredMessage message)
        {
            var myResponseDto = message.GetBody<MyResponseDto>();

            var serialisedMyResponseDto = new JavaScriptSerializer().Serialise(myResponseDto);

            this.cache.StringSet(myResponseDto.ETag, serialisedMyResponseDto);

            message.CompleteAsync();
        }
    }
}
namespace MyConsoleApplicationAsync
{
    public class Program
    {
        public static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                ShowUsage();
                return;
            }

            MainAsync(args).Wait();
        }

        private static async Task MainAsync(string[] args)
        {
            var baseAddress = args[0];
            var apiRoute = args[1];
            var querystring = args[2];

            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(baseAddress);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/json"));

                // request with querystring.
                var response = await client.GetAsync(apiRoute + querystring);

                // request has been accepted (the first response) or
                // response is not yet available in the server's cache.
                while (response.StatusCode.Equals(HttpStatusCode.Accepted) ||
                       response.StatusCode.Equals(HttpStatusCode.NotModified))
                {
                    // use the suggested timeout from the server.
                    var retryAfter = response.Headers.RetryAfter.Delta;
                    if (retryAfter.HasValue)
                    {
                        Thread.Sleep(retryAfter.Value);
                    }

                    // set the ETag (EntityTag) to check in the server's cache.
                    client.DefaultRequestHeaders.IfNoneMatch.Clear();
                    client.DefaultRequestHeaders.IfNoneMatch.Add(
                        response.Headers.ETag);

                    // check cache.
                    response = await client.GetAsync(new Uri(apiRoute));
                }

                // should be 200 (OK) but may be an error code.
                Console.WriteLine(response.StatusCode);
                Console.WriteLine(response.ReasonPhrase);
                Console.WriteLine(response.Content.ReadAsStringAsync());
            }
        }

        private static void ShowUsage()
        {
            var usage = new StringBuilder("Call the Web API.");
            usage.AppendLine("Usage:");
            usage.AppendLine("myApi baseAddress apiRoute querystring");
            usage.AppendLine("Example:");
            usage.AppendLine("myApi 'http://localhost:8080/' 'api/my' '?age=42&postcode=W1A4WW'");
            Console.WriteLine(usage.ToString());
        }
    }
}
namespace WebRole.Controllers
{
    public class MyController : ApiController
    {
        private readonly ICache cache;

        private readonly IMyRequestQueue myRequestQueue;

        public MyController(
            ICache cache,
            IModellerRequestQueue myRequestQueue)
        {
            this.cache = cache;
            this.myRequestQueue = myRequestQueue;
        }

        public HttpResponseMessage Get([FromUri] MyRequest myRequest)
        {
            // the client's request is placed on the queue and they receive a
            // 202 (Accepted) and an ETag (EntityTag). They poll with the ETag in
            // their If-None-Match header. If the resource is not available
            // yet they will receive a 304 (Not-Modified) and they must continue
            // to poll. When the response is available then it will be written
            // into the cache over the value of the original request. Now the ETag
            // points to the result. On the next request the client will receive
            // a 200 (OK) and their resource.

            // try to get the request's ETag.
            var clientETag = this.Request.Headers.IfNoneMatch.FirstOrDefault();

            // if the If-None-Match header is supplied then
            // this is a polling request for the resource.
            if (clientETag != null)
            {
                return this.HandlePollingRequest(clientETag);
            }

            // if the If-None-Match header was not supplied then
            // this is the first request for the resource.
            // set an Accepted response message.
            var response = new HttpResponseMessage(HttpStatusCode.Accepted);

            // set a weak ETag.
            var requestUri = this.Request.RequestUri.ToString();
            var serverETag = ETag.Create(requestUri);
            response.Headers.ETag = new EntityTagHeaderValue(serverETag, true);

            // set a "retry after" suggestion.
            response.Headers.RetryAfter = new RetryConditionHeaderValue(new TimeSpan(0, 0, 10));

            this.cache.StringSet(serverETag, requestUri);

            var myRequestDto = this.mapper.Map<PlanRequestDto>(myRequest);
            myRequestDto.ETag = serverETag;

            // put the work on the queue.
            this.myRequestQueue.Client.SendAsync(
                new BrokeredMessage(myRequestDto));

            return response;
        }

        private HttpResponseMessage HandlePollingRequest(EntityTagHeaderValue clientETag)
        {
            HttpResponseMessage response;

            var cachedValue = this.cache.StringGet(clientETag.Tag);

            if (cachedValue == null)
            {
                // cache may have expired or
                // the client may have an incorrect ETag.
                return
                    this.Request.CreateResponse(
                        HttpStatusCode.PreconditionFailed,
                        Errors.NoETag);
            }

            // get the hash of the value in the cache.
            var serverETag = ETag.Create(cachedValue);

            // check the request ETag against the value in the cache
            // to see if the resource has been updated.
            if (clientETag.Tag.Equals(serverETag))
            {
                // if they match then the resource isn't available yet so
                // return 304 (Not-Modified).
                response = new HttpResponseMessage(HttpStatusCode.NotModified);

                // add the ETag for the next polling request to use.
                response.Headers.ETag = clientETag;

                // set a retry after suggestion.
                response.Headers.RetryAfter = new RetryConditionHeaderValue(new TimeSpan(0, 0, 10));
            }
            else
            {
                var myResponseDto = new JavaScriptSerializer().Deserialise<MyResponseDto>(cachedValue);
                var myResponse = this.mapper.Map<MyResponse>(myResponseDto);

                // the resource is available now so
                // the updated resource should be returned.
                response = this.Request.CreateResponse(HttpStatusCode.OK, myResponse);

                // set the ETag for completeness.
                response.Headers.ETag = clientETag;
            }

            return response;
        }
    }

    public static class ETag
    {
        public static string Create(string cachedValue)
        {
            byte[] bytes = Encoding.ASCII.GetBytes(cachedValue);
            byte[] hash = SHA256.Create().ComputeHash(bytes);

            // ETag must be quoted string.
            var builder = new StringBuilder("\"");

            foreach (byte t in hash)
            {
                builder.Append(t.ToString("x2"));
            }

            builder.Append("\"");

            string serverETag = builder.ToString();

            return serverETag;
        }
    }
}

以上是关于csharp Azure WebRole的WebAPI控制器,可以管理需要很长时间才能完成的请求。的主要内容,如果未能解决你的问题,请参考以下文章

在 Azure WebRole 上自动启动 WCF

WindowsAzure上把WebApp和WebService同时部署在一个WebRole中

处理 Azure 暂存疯狂 URL

Windows Azure 服务总线 - 一般问题

Azure Web 角色通过 Autoscaler 不断回收

如何在 Windows azure 中有效扩展?