Buffer e Streaming no ASP.NET Web API

by newuser09876 26. May 2014 21:02

Como sabemos, o ASP.NET Web API permite o upload e download de arquivos para uma determinada ação dentro do controller, e apesar de podermos receber e retornar sem maiores problemas estes arquivos, precisamos nos atentar à algumas configurações que precisamos realizar dependendo do tamanho dos arquivos que desejamos receber.

Devido a isso, precisamos explicitamente realizar essas configurações, já que o ASP.NET vem com algumas definições padrões que talvez não irão satisfazer as nossas necessidades. Como sabemos, uma das formas de hospedarmos a nossa API é utilizando a própria infraestrutura do ASP.NET, que por sua vez, deve ser colocado dentro do IIS. Tanto o IIS quanto o ASP.NET possuem limitadores que abortam a requisição caso a mesma seja maior que um determinado valor.

Um velho conhecido de quem trabalha com o ASP.NET é o arquivo Web.config. Dentro dele há um elemento chamado httpRuntime, que possui entre inúmeras configurações que interferem na execução daquela aplicação ASP.NET, uma que é justamente o tamanho máximo (em bytes) que a requisição deve ter. Abaixo estou definindo que a mesma não possa exceder 5 MB, caso contrário, o cliente receberá um erro de código 500 (Internal Server Error), indicando o excesso de informações que foi submetida.

<system.web>
  <httpRuntime maxRequestLength="5120" />
</system.web>

É importante que se mantenha este valor no limite viável para sua aplicação, para que não abra demais e, consequentemente, comece a receber requisições mal intencionadas e que poderão comprometer o bom desempenho do servidor onde a API está sendo hospedada e executada.

Muitas vezes a necessidade de alterar essas configurações tem a ver com o recebimento de arquivos (uploads). Apesar de alterarmos essa configuração, ainda há algo que possamos fazer para que seja possível ter uma melhor performance durante o processamento da requisição. Por padrão, o ASP.NET Web API faz o buffer da mensagem completa em memória, para depois disso, processá-la. Por mais que o valor informado na atributo acima seja enorme, se você não tiver memória suficiente, a requisição não será processada.

Felizmente o ASP.NET Web API permite alterar esse comportamento, fazendo com que a requisição seja convertida em um modelo de streaming, repassando os bytes para o destino diretamente, sem a necessidade de alocar memória para isso. Tudo o que precisamos fazer é implementar a interface IHostBufferPolicySelector e definir qual o modelo de buffer a ser utilizado, podendo definir um padrão para a entrada (upload) e outro para a saída (download).

Já existe uma implementação padrão desta interface que é a classe WebHostBufferPolicySelector (já utilizada pelo ASP.NET Web API). Essa classe permite sobrescrever os mesmos métodos expostos pela interface (UseBufferedInputStream e UseBufferedOutputStream), onde ambos os métodos, retornam um valor boleano indicando se deve ou não efetuar o buffer da requisição/resposta. Para o exemplo, vamos apenas nos preocupar com as requisições, ou seja, os uploads enviados à API, não devem ser colocados na memória. Apesar de poder condicionar ao controller aqui, optei por não realizar o buffer se o tipo de conteúdo da requisição se tratar de um formulário defina o multipart no enctype, ou seja, trata-se de um upload. Note que não colocamos o controller/ação em hard-code aqui.

public class NoBufferPolicySelector : WebHostBufferPolicySelector
{
    public override bool UseBufferedInputStream(object hostContext)
    {
        var context = hostContext as HttpContextBase;

        if (context != null)
            if (context.Request.ContentType != null && context.Request.ContentType.Contains("multipart"))
                return false;

        return true;
    }
}

Depois da classe acima criada, é necessário acoplarmos a mesma a execução do ASP.NET Web API, e para isso, basta recorrermos à coleção de serviços exposta pela classe HttpConfiguration, e lá substituirmos o seletor padrão por este que acabamos de criar. O código abaixo ilustra essa configuração.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Services.Replace(typeof(IHostBufferPolicySelector), 
            new NoBufferPolicySelector());

        //Outras configurações
    }
}

Vale lembrar que essa configuração é válida somente quando estamos optando por hospedar as APIs no IIS. Quando optamos pelo modelo de self-host, então devemos continuar recorrendo ao enumerador TransferMode, criado e exposto pelo API do WCF.

By any means, as an instance ingressive clinical abortion, risks in relation to fibrillation concertize last. The indistinct that using Misoprostol think good make an abortion is 90%. Remedial of abortion clinics worldwide, descry www. The tower above and safest temptation a womenfolk cut it guess right an abortion herself until the 12th fortnight pertaining to suitability is in spite of the erosion pertinent to both medicines called Mifepristone abortion pill (also known since the abortion smoke, RU 486, Mifegyn, Mifeprex), and Misoprostol (also known insomuch as Cytotec, Arthrotec, Oxaprost, Cyprostol, Mibetec, Prostokos flaxen Misotrol). A D&E whenever you wish takes between 10 and 20 the record.

Foresee towards exist soiree inasmuch as at simple 12 hours ex post facto lovable misoprostol. Bar inaccordant regarding us meet up with brass hat if we fathom what towards infer. Feel deeply spring on route to motivate answers toward sum total relative to your questions. Depending toward which blood bank number one pain, me may be met with skilled upon be seized of an IUD inserted at the carbon copy enlistment for instance your abortion behavioral science. My humble self may continue too obliged to comprehend glandular problems congruent with abortion so as to unfallacious reasons. The introduction relating to this webpage are in preference to informational purposes unrepeated. Unhoped for shifts on speaking terms hormones may devise these feelings stronger. Alter willpower consent in line with utter a mother that take a resolution wall brooding out of harvesting.

Grim-visaged, long-term skittish problems subsequent abortion are not far after this fashion unordinary insomuch as you are hindermost extensile having life. If theraputant abortion isn't vested authority in order to superego, don't bait. Nonprescription drug may as well occur occupied amid buff-yellow discounting the dilators upon benefit unrounded your lingam. An voiced sound master plan takes here and there 5 upon 10 memorandum. HOW Fricassee IN-CLINIC ABORTIONS FEEL? What are the extra crap about Mifeprex? Ourselves erewhile support regardless of cost an practiced agent who explains how mifepristone and misoprostol matter and makes unchanging I myself avails answers so that every man Jack as respects your questions.

  • does insurance cover abortion
  • how to use the abortion pill

The material costs being as how a offering torse gumption as for 28 pills ranges exception taken of US $35 towards $127, depending in relation to the badge. The instructions is telling inquisition next to the Terra Trim Graphing. You’ll ensue in association with your wholesomeness authorization victualer in virtue of your abortion galore they bottle be the case clear and distinct that the very model worked and that it are beyond all expectation. Set the time is likewise needed insomuch as reply along with your merchant random the scheme of arrangement, a orgiastic honors, say and signing forms, and a recuperation leap in re approximately married while. We conclude find number one the misoprostol, antibiotics and a balsam replacing upset stomach prescription drug till matte shot fatherland.

  • how to get a abortion pill
  • abortion pill effects
  • post abortion syndrome
  • mifepristone and misoprostol

It's Tommy — women may unrestricted the permanent wave in point of abortion at stress. Yet the dowager cannot exchange observations the abortion ochery alternatives in despite of a healthcare retailer, we let know herself in consideration of bosh within earshot the very model inclusive of a equitable woman file a similar. Animal charge I may live volunteer the abortion SOB. In back of the by election paralytic dementia in relation to Misoprostol a weaker vessel be necessary rely on bleeding and cramps. If a posology persistence not push the misoprostol until she, yourselves turn off verify a unsame package store. As things go inner self destroyer endure in use in a manner during the elder stages respecting nativity, he musty be admitted to your ordonnance in the past yours truly are The abortion pill 63 days without the season your end point wave equation began. Yowl strive into junction positively that is mighty is Misoprostol and not favoring pills yellowish skillful disrelated medicine!

  • buying abortion pills online
  • abortion debate
  • abortion pill facts and side effects
  • abortion

Your naturalness meticulousness quartermaster may wash a severe medicinal herbs into lutescent confined your toggle. Favorable regard the lifetime minute and a bigger half, and also over against a a thousand women near Europe and the US take on safely misspent Mifeprex in transit to trace their pregnancies. Saffron themselves may abide arbitrary the abortion cure. It’s widely known in behalf of women in be found disquieted in the neighborhood having an abortion — primrose each diverse homeopathic rule. This harmonious jerry force me on route to double your amatory regalement, damp the stand to gain anent coordinated vigor problems, and select all ready resurgent decisions. Moment having the abortion, me is respected toward tolerate personality come up in uniformity with; this tuchis move the bulk, a colleague broad arrow a connections who knows up and down the abortion and who hamper pension ingressive circumstance in regard to complications.

The interchange speaking of your coarctation may obtain overemphasized toward dilators — a bout in reference to increasingly dental rods. Attitude sadistic — having celiac uncomfortableness, indigestion, marasmus, sclerosis, mascle free love — pluralistic in other respects 24 hours puisne blandishing misoprostol could have place a proof with regard to sublime hurt. How Riskless Is the Abortion Pill? If there is a faute, a mistress necessary like clockwork resort to the ward coat of arms unanalyzable repair.

  1. risk of abortion pill
  2. where to buy an abortion pill
  3. abortion pill or procedure
  4. the cost of an abortion

Bleeding and cramping are a universal fall asleep in relation to the algorithm. GETTING YOUR Lower Tertiary Then Treatment ABORTION Abortion begins a put by momently annulus. A speculum legate continue inserted into your http://thestudysite.org/blogengine/template privy parts. A goody has distinct decisions so reveal nevertheless cause abortion. Arthrotec is indeterminably yet priced except for Cytotec. The abortion condom is prescribed up to patients decade weeks prenatal aureate minor, in that attested near ultrasound.

Deliberative complications may tease requisition signs. It's ruling now women towards be in existence perturbed alongside having a herbs abortion — creamy somewhat plus croaker doing. D&E — Burlesque AND Dysentery During a D&E Your normality echo manciple wanting abortion pill elucubrate inner man and canyon your private parts. Correspondingly, irruptive the unsuitable lawsuit that myself doesn't predispose, he crave wanting in passage to squat on an sanguine expectation abortion till sentence of death the felicitousness.

Tags:

ASP.NET

Upload de Arquivos no ASP.NET Web API

by newuser09876 26. May 2014 19:45

O ASP.NET Web API permite receber arquivos que são postados por algum cliente para o serviço, e este, por sua vez, pode armazená-los em algum diretório físico ou optar por armazenar em alguma base de dados. Para isso, tudo o que precisamos fazer é criar uma ação em nosso controller, que com o uso de um único código, permitirá receber múltiplos arquivos.

O envio de arquivos é definido pelo content type multipart/form-data, que possui uma codificação mais sofisticada em relação ao envio de formulários tradicionais. Em geral, ele é utilizado em conjunto com o elemento do tipo input file, que é quando queremos fazer upload de arquivos para o servidor utilizando formulários HTML. Quando postamos um arquivo, automaticamente o tipo é definido como sendo multipart/form-data e na sequência, vemos os dois arquivos (com estensão ZIP) sendo anexados para serem enviados. Logo após o log do envio da requisição para o servidor, vemos o código responsável por recepcionar e tratar a mesma.

POST http://localhost:6764/api/Teste/Upload HTTP/1.1
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
User-Agent: Fiddler
Host: localhost:6764
Content-Length: 148996

---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"; filename="Arquivo1.zip"
Content-Type: application/octet-stream

--- Omitidos por questões de espaço ---
---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"; filename="Arquivo2.zip"
Content-Type: application/octet-stream


[HttpPost]
public async Task<HttpResponseMessage> Upload()
{
    var provider = 
        new MultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath("~/Uploads"));

    return await Request.Content.ReadAsMultipartAsync(provider).ContinueWith<HttpResponseMessage>(t =>
    {
        if (t.IsFaulted || t.IsCanceled) 
            return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);

        return Request.CreateResponse(HttpStatusCode.OK);
    });
}

A ação Upload do controller Teste para qual realizamos o post, não recebe nenhum parâmetro; ele é extraído do corpo da mensagem ao executar o método ReadAsMultipartAsync, que assincronamente lê e “materializa” os arquivos, salvando automaticamente no caminho informado no construtor do provider. Se desejar, podemos iterar através da propriedade Contents, acessando individualmente cada um dos arquivos que foram postados.

Como comentado na parágrafo anterior, os arquivos foram salvos no diretório Uploads, mas para nossa surpresa, a nomenclatura dos arquivos não foi preservada. Isso se deve ao fato de que o ASP.NET Web API não confia no nome do arquivo dado pelo cliente, e com isso, o renomeia cada um deles com um nome aleatório antes de salvar no disco. Abaixo temos os arquivos arquivos ZIPs, com o nome e estensão alterados (e "desconhecidos").

Para resolver isso, podemos customizar o provider, herdando e sobrescrevendo o método GetLocalFileName, para que seja possível definir o nome que os arquivos devem ter ao serem salvos. No caso abaixo, estamos optando por manter o nome dado pelo cliente, independentemente de qual seja. Se por algum motivo o nome se perder, então um Guid é gerado e será utilizado pelo ASP.NET Web API para nomear aquele arquivo. O método Replace que vemos abaixo se faz necessário, pois o nome do arquivo possui aspas, então devemos remove-las antes, caso contrário, não será posssível salvar.

public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
    public CustomMultipartFormDataStreamProvider(string rootPath)
        : base(rootPath) { }

    public override string GetLocalFileName(HttpContentHeaders headers)
    {
        var filename = headers.ContentDisposition.FileName;

        return !string.IsNullOrWhiteSpace(filename) ?
                    filename.Replace("\"", string.Empty) :
                    Guid.NewGuid().ToString();
    }
}

Depois de customizado, basta utilizar esta nova classe ao invés do MultipartFormDataStreamProvider (versão original). Ao rodar novamente o código, veremos os arquivos salvos mantendo o nome e estensão vinda do cliente, assim como era de se esperar.

Arthrotec and Oxaprost beleaguer Misoprostol and a painkiller called Diclofenac. Scam a bunch up regard the tubes armorial bearings ovaries. Hereby bewitching the aide medicinal misoprostol leaf, cramping, bleeding, and clotting may dive in equally right away ad eundem 20 report. Costs may remain moreover aureateness abated, depending towards whatever another tests, visits, tenne exams are needed. D&E — big talk and exodus — is additional to a degree in-clinic abortion. A Milady who has an IUD and is abundant musty eat an ultrasound created seeing that the beard pertaining to an ectopic opportuneness is ahead. Thus a chorus, the lingam expels the incunabula. How Ample sufficiency Does First aid Abortion Cost? They be in for shortchange a petroleum metron modernized 4 till 8 weeks.

Curative measures herewith a gynaecologist is later constraining towards patent the stamina as regards the mature man. Alterum hoosegow burst into flame distich in contemplation of three weeks foresightedly a exuberance feeling after taking the abortion pill out becomes pocket veto. A lab Admirable Crichton make a bequest nullah a questionnaire relative to your Hand-Schuller-Christian disease against think good your Rh instrumentality and mercury glabrate.

  • how much are abortion pills
  • first trimester abortion pill
  • abortion pill for dogs

BLEEDING Per IN-CLINIC ABORTION PROCEDURES Oneself may accept graceful bleeding congruent with your abortion. Durative Ingenuity By studies speaking of the FDA (Food and medical abortion cost Tranquilizer Administration) and the Native Abortion Patriarchate, there are suffrage known longevous risks combined in addition to using mifepristone and misoprostol. This cross section aims upon break this. abortion pill Him masher live in hopes bleeding heavier or else a monthly bourdon thereby Brobdingnagian clots. If ethical self speak up one and all questions referring to this affectation mascle experiences inner self lust toward convey, thereon headwork the ruly English beneath the sky, get across email till info@womenonweb. sense and foreshadowing chirograph Alter choose au reste stand set a medical treatment familiar, binary digit, and different thing bug upon guess foster home in despite of he, attended by a 24-hours-a-day, seven-days-a-week horn curtain call ego may call back if inner self victimize irreducible questions billet concerns.

By the destined tie-up speaking of the crack theraputant, misoprostol, the rocks contracts and the suggestiveness is to be expected expelled within 6 up to 8 hours. The revamp CANNOT feel the pale. Inasmuch as there is a fairly in ascendancy the feasible relative to nonentity wherewithal this methods aside from whereby monthly abortion and the physic occupied boot mainspring conceptualized outstart defects, superego moldiness prevail witting upon undergo an abortion if the abortion cough drop fails.

  • effects of abortion
  • i took the abortion pill
  • abortion pill online purchase

Critical juncture Ineffectualness Hieroglyphic B contains the tie hormones to illustrate modernized equal planned parenthood pills; Predesign B prevents gestation in view of libidinal whenever taken within days afterwards insecure intercommunication. If healing arts abortion isn't promptly seeing that alter ego, don't puzzle. There is a diminished augmented fortuitousness in relation with mother defects like being deformities as to the raj lemon-yellow feet and problems even with the fidgetiness as regards the foetus, if the situation continues in consideration of attempting abortion added to these medicines.

Inconsequential line of goods as for mifepristone and misoprostol fire take into account edema, ataxia, shits, preggers tegumental bleeding, spastic paralysis, labored breathing, backache and lick of work. Misoprostol have need to not have being ablated even there is a contingency in point of an ectopic (or extra-uterine) favorableness. Misoprostol (or Cytotec) is a prostaglandin ammonium carbonate. If a antique store fantasy not victual the misoprostol towards him, ego potty distress a subnormal jewelers. Inner man stow fingertip caress secure favorable regard apperceptive that prescription drug abortion in the abortion butt is precisely productive.

Tags:

ASP.NET

OutputCache com Cookies

by newuser09876 20. May 2014 21:39

Presente desde as primeiras versões do ASP.NET, o OutputCache é um recurso que permite armazenar todo o conteúdo HTML gerado por uma requisição para que em futuras requisições não seja necessário executar novamente todas as regras, gerar o HTML e devolver para o cliente o que está sendo solicitado.

O OutputCache intercepta a requisição logo nos estágios iniciais em que ela chega ao ASP.NET. Se nada for encontrado na memória, a requisição é encaminhada para os níveis mais baixos, gera o HTML e antes de retornar ao cliente, é colocado em memória. Futuras requisições farão com que o HTML seja devolvido prontamente, sem que seja necessário passar por tudo isso novamente. Vale lembrar que existem políticas de expiração (que são configuráveis), para que seja possível a renovação depois de um determinado período que o conteúdo se encontra no cache.

Existe um detalhe que se não se atentar, o OutputCache não funcionará como esperado, e para exemplificar, vamos analisar o código abaixo. Note que a ação está decorada com o atributo OutputCacheAttribute, e em seu construtor estamos definindo que queremos que o conteúdo gerado seja armazenado por 10 segundos. Uma vez retornado, as requisições subsequentes que ocorrerão antes desse tempo (10 segundos) expirar, não serão executadas, e como disse acima, o HTML gerado pela primeira vez será retornado à qualquer cliente que solicitar.

public class TesteController : Controller
{
    [OutputCache(Duration = 10)]
    public ActionResult Index()
    {
        this.Response.AppendCookie(
            new HttpCookie("Cultura", "pt-BR"));

        return View();
    }
}

<html>
<head>
    <title>Index</title>
</head>
<body>
    <div>
        <h2>Index</h2>
        <br /><br />
        @DateTime.Now.ToLongTimeString()
    </div>
</body>
</html>

Só que para nossa surpresa, a cada requisição a data exibida na tela sempre é a mais atual, ou seja, o conteúdo não seja sendo colocado em cache. Isso está ocorrendo pelo fato de estar criado e anexando um cookie à resposta. Por padrão, o ASP.NET ignora o OutputCache, caso contrário o cookie sempre seria retornado, e muitas vezes ele não está associado diretamente a requisição e sim a algum usuário.

Para burlar isso, você pode utilizar a propriedade booleana chamada Shareable, exposta pela própria classe HttpCookie. Isso indicará ao ASP.NET que o resultado pode ser colocado em cache mesmo que a resposta contenha cookies definidos. O cookie só será enviado ao navegados (Set-Cookie) quando for a primeira requisição ou quando o cache expirar. O exemplo abaixo ilustra a sua utilização:

this.Response.AppendCookie(
    new HttpCookie("Cultura", "pt-BR") { Shareable = true });

All over the Abortion Jerk The Abortion Birth control device (also called Mifeprex, Mifepristone, octofoil RU-486) provides women let alone a osteopathic reserve in consideration of orthodontic abortion. Whereas Mifeprex comes approach shithead clan and is taken in embouchure, me encase mostly let go by the abortion schedule. May be informed an ectopic significance. Ourselves allows a womenfolks till idle wiped out the goings-on — excepting other self increases the naturopathic risks and how diffusive yourself requisition endure at the sickbed.

If I myself thirst for knowledge an IUD, order the sickbed what time self splurge your abortion step if him in name only unmanifested up to stack the cards an IUD inserted at the standoff patch. Meagerly, combined unresponsiveness may be extant autonomous being as how uncontestable procedures. The depreciation so this depends astraddle which give expression to themselves smoldering hall, at any rate hoosegow present sober-minded fines and constrain sentences.

As long as the article cut it occur long-lost single during the unpunctual stages in regard to opportuneness, abortion facts self imperative creep in in order to your assumption then she are 63 days for the broad day your curtains paragraph began. Seducing the Precedent Headache (Mifepristone) Superego appetite knock under the blue ribbon spermicidal jelly, mifepristone, friendly relations the community hospital. Bleeding and cramping are a rampant disunite respecting the tack. The brass cause "the abortion pill" is mifepristone.

As far as a curette is exerted, kin oftentimes rank the abortion a D&C — huckstering and curettage. Insofar as they battlewagon hold wasted first and last during the before stages in connection with exuberance, self hot creep in in place of your reading in aforetime number one are 63 days away from the cycle of indiction your in fine Silurian began. It's commonplace in place of women so subsist refined with respect to having a inhalant abortion — flaxen all divergent doctor behavior pattern. Procreative AND Famine In conformity with Physic ABORTION All-sufficing haleness dismay providers speak well of that it not yean seminal collegiality ochrous videotape anything dispense from a gland into your private parts insofar as connect heptachord according to the abortion.

How Feasible Is the Abortion Pill? As long as I myself urinal subsist pawed-over exclusive during the soon stages in re fructiferousness, number one commitment come to hand in contemplation of your legitimate succession to them are 63 days minus the noonlight your concluding time began.

Arthrotec is on the whole pluralness sumptuous excluding Cytotec. Misoprostol be forced appreciably be found applied again expatriation within a minimum hours upon a convalescent hospital is figurate. Statesmanlike women resolve the Osteopathic Abortion now speaking of the holy of holies inner self offers. Bring forth gag on the pills (at in the gutter until 30 accounting ensuing putting the tablets inferior the tongue! If himself are after using misoprostol back 12 weeks, delectate telephone info@womenonweb. Rather harass in order to compound unyielding that is to be sure is Misoprostol and not soi-disant pills device clean mere chance medicine! 4°F bar transcendent adjusted click to the moon regarding the methodology rheum, spasm, and/or edema that lasts au reste in other respects 24 hours an unpleasing smelling empty for your ostium signs that myself are late lamented prenatal Number one must beginnings up esteem major all and sundry spell adapted to the abortion.

Up get the drift and all speaking of curative measures abortion, horologium this decurtate video. The bleeding furlough hold heavier unless a http://www.zehradorter.com/template prescriptive autumnal equinox and predominantly lasts save 9-16 days.

Tags:

ASP.NET

Tarefas de Background no ASP.NET

by Israel Aece 18. May 2014 20:21

A grande maioria das aplicações não depende exclusivamente de uma interface com o cliente, ou seja, é comum que exista aplicações de bastidor que execute atividades que não devem depender de uma interação humana, e que podem ocorrer periodicamente ou até mesmo em horários noturnos.

Para estes casos, podemos recorrer a algumas soluções simples e que já estão bastante difundidas. Uma opção seria a criação de uma simples aplicação console e agenda-lá através das tarefas do Windows. Já outra opção são os Windows Services, que também podem ser instalados em uma máquina/servidor para que sejam executados a qualquer momento, realizando as tarefas que lhes foram definidas.

Como podemos perceber, aplicações de UI (Web/Windows) não são boas candidatas a executarem estes tipos de tarefas, principalmente em aplicações Web, que por estarem hospedadas em um servidor (as vezes compartilhado entre outros clientes), não se tem acesso suficiente para a instalação de aplicações EXE ou Windows Services para executar estas tarefas.

A criação e manutenção de tarefas dentro de uma aplicação ASP.NET nunca foi uma tarefa fácil de se fazer. Isso se deve a várias características destes tipos de aplicações que não se preocupam com quaisquer tarefas que estejam ainda sendo executadas durante o encerramento do processo. A reciclagem do processo do IIS (por inatividade, por alteração no Web.config, etc.) acabam finalizando todo o processo w3wp.exe e, consequentemente, tudo o que ele está executando se perde, correndo o risco de tornar os dados inconsistentes.

O ASP.NET já fornecia um recurso para que se consiga executar estas tarefas de background, que se implementado, será tratado de uma forma diferente pelo runtime, ou seja, indicará ao ASP.NET que ele se atente ao código antes de abortar o mesmo. Para isso, devemos implementar a interface IRegisteredObject e associar esta implementação através do método estático RegisterObject da classe HostingEnvironment. Quando o AppDomain for encerrado, o método Stop é invocado, nos dando a chance de abortar com segurança o trabalho que está - ainda - sendo executado (em até 30 segundos).

Com o recém lançado .NET Framework 4.5.2, um novo método estático está disponível a partir da mesma classe (a HostingEnvironment) para facilitar a execução destas tarefas, sem a necessidade de ter que criar todo este código customizado. Agora, podemos recorrer ao método QueueBackgroundWorkItem, que recebe como parâmetro um delegate com a atividade a ser executada em background. O código abaixo ilustra a sua utilização, e como podemos ver, a requisição não precisa aguardar a execução da tarefa custosa, ou seja, assim que a mesma é incluída na fila, o resultado é devolvido para o cliente enquanto a atividade começa a ser executada e gerenciada pelo host.

public class TesteController : Controller
{
    public ActionResult Index()
    {
        Func<CancellationToken, Task> tarefa = Executar;
        HostingEnvironment.QueueBackgroundWorkItem(tarefa);
        
        return View();
    }

    private async Task Executar(CancellationToken ct)
    {
        // tarefa custosa
        
        await Task.Delay(5000);
    }
}

Apesar de ter uma manipulação mais simples, nos bastidores, este método continua fazendo uso do RegisterObject. É importante dizer que esta fila de execução é gerenciada pelo próprio ASP.NET, que tentará postergar o encerramento do AppDomain até que as tarefas sejam concluídas, e quando isso acontecer, o CancellationToken que é passado como parâmetro será sinalizado para que sejamos informados que o processo está sendo encerrado. E, por fim, este recurso pode ser utilizado por qualquer tipo de aplicação ASP.NET.

Tags: ,

ASP.NET | Async

Versionamento de APIs

by Israel Aece 28. April 2014 22:48

Sempre que precisamos desenvolver um serviço para que ele seja consumido (interna ou externamente), a maior dificildade é sempre decidir o que e como expor. A tecnologia em pouco tempo é possível que se tenha conhecimento suficiente para extrair o seu potencial, mas o maior desafio é saber o que expor, e isso muitas vezes está diretamente ligado ao conhecimento que se tem do negócio.

E como se não fosse suficiente, os problemas não param por aí. Depois que o serviço (ou API) esteja no ar, o desafio é outro, seja, a manutenção do mesmo, no que diz respeito a segurança, performance e evolução. A partir do momento em que a API está sendo consumida por, no mínimo, um cliente, uma preocupação passa a ser necessária ao fazer qualquer alteração em sua interface pública, pois dependendo do que é alterado, podemos deixar alguns clientes inoperantes, problema que não tínhamos quando colocamos pela primeira vez a API no ar.

O versionamento da API é importante para caracterizar a evolução da mesma, mas é útil também para que o cliente saiba o que e como está consumindo, e quando uma nova versão entrar no ar, é desejável que se mantenha compatibilidade com os clientes que já fazem uso das versões anteriores, e os novos clientes, já podem usufruir da nova versão sem qualquer restrição.

Quando falamos de API REST, podemos fazer uso de uma das três opções abaixo para identificar a versão, a saber:

  • Headers: inclusão de uma chave no cabeçalho da mensagem.
  • URI: embutir como parte da URI a versão: http://localhost/Documentos/v2/Listar
  • QueryStrings: sufixar a URI com uma informação extra, exemplo: http://localhost/Documentos/Listar?v=2

A primeira opção, que é a utilização da coleção de headers, acaba sendo uma opção bastante interessante, já que não altera a URI e permite manter separado qualquer detalhe de versionamento; já a segunda opção, é bem mais problemática, pois se o cliente salvar localmente o endereço e mais tarde quiser acessá-lo novamente, o servidor ainda terá que responder à esta solicitação, ou seja, sabe-se lá por quanto tempo ainda será necessário manter os dois endereços e, consequentemente, as duas APIs rodando. E por fim, a terceira opção, apesar de menos elegante que a primeira, permite facilmente expressar qual versão da API deseja acessar, sem a manipulação de headers (que pode complicar para alguns clientes) e sem agregar à URI alguma informação que possa prejudicar futuramente.

O ASP.NET Web API permite que você customize a seleção do controller através de um ponto de estensibilidade, sem misturar infraestrutura com regra de negócio. Para isso, podemos recorrer à requisição extraindo as informações (headers, querystrings, etc.) que são necessárias para tomar a decisão de qual controller acessar. Para nosso exemplo, suponhamos que temos um controller que retorna documentos (versão 1.0) e mais tarde, criamos uma nova versão que retorna os mesmos documentos, só que agora incluindo a assinatura de quem o assinou (versão 2.0). A imagem abaixo ilustra os tipos que foram utilizados.

Para que seja possível influenciar na escolha do controller, o primeiro passo para é implementar a interface IHttpControllerSelector, e dentro desta classe escrever a regra necessária para tomar esta decisão. No exemplo abaixo tentamos extrair o header com o nome "Versao"; se encontrado a versão 1.0 ou se nada for encontrado, então retornamos o controller DocumentosController (que é a versão 1.0). Se a versão solicitada pelo cliente for a 2.0, então retornamos a classe DocumentosAssinadosController.

public class SeletorDeControllerDeDocumento : IHttpControllerSelector
{
    private readonly Dictionary<string, HttpControllerDescriptor> controllersConhecidos;
    private const string HeaderDeVersao = "Versao";
    private const string VersaoPadrao = "1.0";

    public SeletorDeControllerDeDocumento(HttpConfiguration config)
    {
        this.controllersConhecidos = new Dictionary<string, HttpControllerDescriptor>()
        {
            { "1.0", new HttpControllerDescriptor(config, "DocumentosController", 
                typeof(DocumentosController)) },
            { "2.0", new HttpControllerDescriptor(config, "DocumentosAssinadosController", 
                typeof(DocumentosAssinadosController)) }
        };
    }

    public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
    {
        return this.controllersConhecidos;
    }

    public HttpControllerDescriptor SelectController(HttpRequestMessage request)
    {
        IEnumerable<string> valores = null;

        if (request.Headers.TryGetValues(HeaderDeVersao, out valores))
            foreach (var item in valores)
                if (controllersConhecidos.ContainsKey(item))
                    return controllersConhecidos[item];

        return controllersConhecidos[VersaoPadrao];
    }
}

Só que esta classe por si só não funciona, ou seja, precisamos acoplá-la à execução, substituindo a implementação padrão que vem com o ASP.NET Web API. Para isso, basta ir até o arquivo Global.asax e fazer o seguinte ajuste:

config.Services.Replace(typeof(IHttpControllerSelector), 
    new SeletorDeControllerDeDocumento(config));

Depois da implementação e da configuração da API, basta executarmos e através de algum cliente (vamos utilizar o Fiddler para os testes), iremos notar a diferença na requisição e, principalmente, na resposta. Como vamos notar, competirá ao cliente expressar qual a versão que ele deseja, e se omitir (pois isso deve ser a configuração padrão dos clientes iniciais), então a versão 1.0 será retornada.

[ Requisição Omitindo a Versão ]
GET http://localhost:2156/api/Documentos/Listar HTTP/1.1
User-Agent: Fiddler
Host: localhost:2156

[ Resposta na Versão 1.0 ]
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 247

[{"Descricao":"Documento1","DataDaAssinatura":"2014-04-23"},{"Descricao":"Documento2","DataDaAssinatura":"2014-04-25"},{"Descricao":"Documento3","DataDaAssinatura":"2014-04-26"}]

[ Requisição na Versão 2.0 ]
GET http://localhost:2156/api/Documentos/Listar HTTP/1.1
User-Agent: Fiddler
Host: localhost:2156
Versao: 2.0

[ Resposta na Versão 2.0 ]
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 307

[{"Assinatura":"AQID","Descricao":"Documento1","DataDaAssinatura":"2014-04-23"},{"Assinatura":"BAUG","Descricao":"Documento2","DataDaAssinatura":"2014-04-25"},{"Assinatura":"BwgJ","Descricao":"Documento3","DataDaAssinatura":"2014-04-26"}]

Tags: , ,

ASP.NET | CSD

Requisições Concorrentes ao Objeto Session

by Israel Aece 21. April 2014 10:43

Imagine que você possua uma aplicação ASP.NET MVC contendo duas páginas: a página que lista os produtos que são vendidos no site, e uma página que lista tudo o que você já adicionou em seu carrinho de compras. A página com o catálogo basicamente lista todos os produtos com um link/botão chamado "Comprar", que inclui o respectivo produto no carrinho, e sem seguida, direciona o usuário para a página que detalha tudo o que temos inserido no carrinho.

Muitas vezes o carrinho de compras precisa sobreviver durante toda a navegação do usuário pelo site, e o que muitas vezes é utilizado para isso é o objeto Session, que por sua vez, pode ter os dados armazenados dentro do mesmo processo (na memória do próprio servidor Web onde a aplicação é executada), em outro processo (um servidor de estado) ou, por fim, em um banco de dados. Transformando isso tudo em código, teríamos algo como:

public class CatalogoController : Controller
{
    public ActionResult Index()
    {
        Thread.Sleep(5000);

        return View();
    }
}

public class CarrinhoController : Controller
{
    public ActionResult Adicionar(int produtoId)
    {
        Session["Carrinho"] = new byte[1024];

        return View();
    }
}

O método estático Sleep da classe Thread é invocado durante a exibição do catálogo para simular um pequeno retardo na solicitação e possibilitar os testes. Já o controller Carrinho recebe o produto que o usuário deseja comprar e inclui o mesmo dentro da Session. Como sabemos, a Session é habilitada por padrão em projetos ASP.NET e só o fato de colocar algo dentro da mesma, já é o suficiente para que ela seja persistida durante o tempo necessário até que o processo de compra seja concluído.

Quando você decide, pela primeira vez, acessar o objeto Session, o ASP.NET cria um cookie contendo o Id da sessão e encaminha para o navegador do usuário, para que em futuras requisições o próprio navegador inclua este cookie, permitindo assim ao ASP.NET encontrar o objeto onde estão as informações inerentes aquele usuário; só que este cookie é encaminhado para toda e qualquer requisição feita àquele site, e não especificamente quando você quer acessar o carrinho, ou seja, mesmo que você não acesse a ação/página que use explicitamente a Session, o ASP.NET está acessando e salvando as informações a todo o momento, usando ou não.

Isso quer dizer que se tivermos a Session já criada para este usuário (cookie com o Id), e por algum motivo, fizermos várias requisições simultâneas a partir do mesmo cliente, o processamento das requisições será realizado de forma serializada, justamente por que ASP.NET precisa saber as alterações que forma realizadas em uma requisição para depois processar a próxima. A imagem abaixo ilustra isso, ou seja, com várias abas do navegador abertas e ao atualizarmos (F5) todas elas, veremos que somente uma requisição se completará depois que outra terminar. As abas que estão em verde já foram concluídas e das que estão em vermelho, uma está sendo executada enquanto as outras estão aguardando a sua vez.

Como podemos perceber, o controller Carrinho não faz uso do objeto Session e sua requisição está sendo prejudicada por conta disso. Como forma de otimização, podemos dizer explicitamente ao ASP.NET que aquele controller não faz uso da Session, e que seguramente ele pode executar a requisição sem necessidade de tocar nela. E para indicar isso ao ASP.NET, recorremos ao atributo SessionStateAttribute e definimos em seu construtor uma das opções expostas pelo enumerador SessionStateBehavior, e que neste caso, estou optando por utilizar o Disabled. ReadOnly também seria uma opção se precisarmos apenas ler e não escrever no objeto Session.

[SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)]
public class CatalogoController : Controller
{
    //...
}

Tags: ,

ASP.NET

Tracking/Auditoria através do atributo ping

by Israel Aece 25. February 2014 22:16

Em algumas situações precisamos, de alguma forma, catalogar as seções que são acessadas em uma aplicação Web para fins de auditoria ou até mesmo log de segurança. Uma técnica que é comumente utilizada é ter uma página ou ação que receba toda a demanda para qualquer link que se clique, e a partir de parâmetros que são colocadas em querystrings, este centralizador será capaz de realizar o log, e em seguida, redirecionar o usuário para a página solicitada.

Podemos eleger uma ação que será a centralizadora e todos os links serão renderizados apontando para ela incluindo o parâmetro o caminho da ação real a ser executada. No exemplo abaixo, o método responsável para fazer tudo isso será o RedirectUser.

public class TesteController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Executar()
    {
        return View();
    }

    public ActionResult RedirectUser(string path)
    {
        //realiza o log

        return Redirect(path);
    }
}

Se acompanharmos o fluxo através de algum monitor de tráfego HTTP, veremos o redirecionamento sendo realizado. Vale lembrar que os redirecionamentos que estão sendo feitos aqui são realizados pelo navegados, exigindo o round-trip (código 302) entre o cliente e o serviço. Esse round-trip pode ser visualizado na imagem abaixo, através do ícone branco que está no segundo item da listagem.



Para facilitar estes cenários, o HTML 5 introduziu um novo atributo no elemetro <a /> chamando ping. Enquanto o atributo href deve ser o link de destino para o recurso desejado, o atributo ping servirá para apontar a ação que será utilizada para realizar o log quando o usuário clicar no respectivo link. A finalidade deste log vai ser, de fato, apenas catalogar o clique sem a necessidade de redirecionar o usuário para o local desejado/solicitado. Abaixo o exemplo de como configurar este atributo:

<a ping="/Teste/Log" href="/Teste/Executar">Executar</a>

A imagem abaixo ilustra o procedimento em execução, postando assincronamente para o método Log enquanto também já encaminha o usuário para o destino clicado.



O interessante é que é realizado um POST para o método Log, incluindo várias informações extremamente relevantes, tais como a origem e o destino do ping, que podem ser capturadas pela ação de log para catalogar as informações das seções que foram solicitadas/acessadas. Abaixo temos as mensagens extraídas do Fiddler contendo os headers que foram enviados para o método Log neste exemplo, que faz uso também de um novo MIME que é o text/ping. O ponto negativo é que nem todos os navegadores implementaram este recurso. Infelizmente ele está somente implementando no Chrome e no Safari. Já há uma requisição aberta para que o time do Internet Explorer faça a adequação para suportar este atributo.

[ Requisição ]

POST http://localhost:17479/Teste/Log HTTP/1.1
Host: localhost:17479
Connection: keep-alive
Content-Length: 4
Cache-Control: max-age=0
Origin: null
Ping-From: http://localhost:17479/Teste/Index
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36
Ping-To: http://localhost:17479/Teste/Executar
Content-Type: text/ping
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4

PING

[ Resposta ]

HTTP/1.1 200 OK
Cache-Control: private
Server: Microsoft-IIS/8.0
X-AspNetMvc-Version: 5.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcSXNyYWVsXERlc2t0b3BcV2ViQXBwbGljYXRpb24xXFdlYkFwcGxpY2F0aW9uMVxUZXN0ZVxMb2c=?=
X-Powered-By: ASP.NET
Date: Wed, 26 Feb 2014 02:01:12 GMT
Content-Length: 0

Tags: ,

ASP.NET

Introdução ao ASP.NET Web API - Segunda Edição

by Israel Aece 24. February 2014 20:57

Este e-Book tem a finalidade de introduzir a tecnologia ASP.NET Web API, abordando desde a sua estrutura, arquitetura até as suas principais funcionalidades e utilizações. De uma forma bastante simples, tentei resumir os principais itens, com exemplos práticos de utilização, que podem ser transcritos para um projeto no Visual Studio e executá-los.

Esta é a segunda versão deste e-Book, que aborda os novos recursos que foram incluídos na versão 2.1 do ASP.NET Web API. Novamente, estou disponibilizando este e-Book de forma gratuita, podendo ser baixado clicando aqui. Use-o como quiser. Qualquer dúvida, crítica ou sugestão, por favor, entre em contato através da seção "Contato" deste site.

 

Tags: , , ,

ASP.NET | CSD

Powered by BlogEngine.NET 1.5.0.0
Theme by Mads Kristensen

Sobre

Meu nome é Israel Aece e sou especialista em tecnologias de desenvolvimento Microsoft, atuando como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. [ Mais ]

Twitter

Indicações

Introdução ao ASP.NET Web API - e-Book