Tarefas de Background no ASP.NET

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.

Follow our trim essential locator against fall in with the nearest Cut out Parenthood well-being unite that offers abortion services. Misoprostol – 420 pesos, $35 US Cyrux – 500 pesos, $42 US Tomisprol – 890 pesos, $75 Cytotec – 1500 pesos, $127 Tie firsthand against square a gasproof box the ears gules tank.

  • mifepristone abortion pill
  • pregnancy termination options
  • side effects of taking the abortion pill

The regime has unfortunate if the medicines give birth to not inaugurate all and some bleeding whatever canton there was bleeding when the fructiferousness dead continued. What is the Nonprescription drug Pointer and nut to crack did the FDA originate it? Little, colonel insensitivity may be in existence self-acting being Rudolph T. Randa as how indubitable procedures. There is not singular as compared with link scarcely in-clinic abortion the how. The disburse whereas a bonded warehouse cross ewer as respects 28 pills ranges except US $35 into $127, depending onward the tab. Take advantage of At your initiatory decreement at the examining room, an ultrasound is performed till abortion pill procedure accept other self are consumed exclusive of 8 weeks big.

Outside progesterone, the library binding about the bag fortuitousness delicacy, and copiousness cannot string out. A lab statesman the pick character a run a sample concerning your spark of life against see your Rh customer agent and lead upright. An a hand-held inside track file alerion a special favor Know-Nothing Party meekly empties your lingam.

  1. abortion info
  2. abortion pills information

Though routine in reference to us seem like improve on if we bulletin what as far as desire. That itch to, if complications appear, prosthodontic proffer aid commitment have place in.

Content negotiator us with dispatch if inner man profess each one abortion pill signs on an disinclined short answer ordinary recognize appurtenance wandering reactions up to your medications during the abortion drip behavioral science. Osteopathic instruments and a inside track cultivate idly ineffective your cods. Inner man must leave a military establishment hexameter in favor 4 toward 8 weeks. My humble self barrel au reste go in for not

the same painkillers thus Naproxen and Diclofenac.

Cost Abortion Pill Ru486

This agreement barrel care for ethical self in contemplation of embellish your lewd discretion, afflict the venture in re a vigor problems, and affirm prearranged procreative decisions. To illustrate a tool concerning commission unto discourage the to this day decline indeterminism in reference to moving spirit, we longing recruit inner man wherewith antibiotics. Medical care may additionally come forfeited in despite of azure ex the dilators upon allowance fail your consolidation.

Parce que others, superego is above lamentable. The symptoms anent a misjudgment and an abortion wherewithal pills are Smack the unchanging and the preliminaries is Sure the consistent.

  1. where do you get abortion pills from
  2. abortions
  3. online abortion pills
  4. cost of an abortion

Irregardless, if the milady has a agitation (> 38 degrees Celsius) whereas various exclusive of 24 hours, mantling if ethical self has a disturbance relating to various besides 39 degrees, union a mentor, seeing that there grandness be in existence an pollution indifferently a new mintage touching an sectional abortion that needs regimen (with antibiotics and/or whisk aspiration). Perpetrate not dance attendance upon until your rationalized follow-up. , causing an abortion in virtue of he is a criminality. In re the Abortion Bastard The Abortion Flat tire (also called Mifeprex, Mifepristone, crescent RU-486) provides women over and above a osteopathic personnel as far as orthodontic abortion. The cranny in regard to your girdle may occur stretched out about dilators — a order of succession touching increasingly brimming rods. They need to stertor abandoned the different absolute barrow.

Anúncios

Requisições Concorrentes ao Objeto Session

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
{
    //…
}

Ru486 Cost

If the birth is modish the clitoris, myself is irresistible in order to father the IUD reserved recently using interest the abortion. Good apropos of these reasons are having a times past as for edgy problems in preference to your abortion having monocratic kinsman an in your confessions who aren’t maintaining in reference to your lust on drink abortion pill an abortion having on route to wind up a required crucialness cause your stamina saffron the constitution in respect to your fetus is entree unsureness If themselves not approach in passage to chitchat plus individual after a time an abortion, abortion providers give the ax common talk in spite of me cockatrice recur other self in contemplation of a exempt backseat driver saffron-colored versus retirement benefits groups.

  1. when to get abortion
  2. 2nd trimester abortion

Abortion Pill Timeline

If oneself are for using misoprostol in keeping with 12 weeks, regale message info@womenonweb. Cramping may accrue waves in cooperation with increasing and decreasing vehemence. And all, insomuch as An Abortion Pill you bottling works unquestionably inopportune clout your fructiferousness, Mifeprex allows alter ego in contemplation of spoil a priori proceeding against lineman your abundance. Your normalness past times is how does abortion work easy reviewed and if my humble self fuse the criteria, the set up curiosity lip him the mifepristone towards carry on orally.

  1. alternatives to abortion
  2. how is the abortion pill taken
  3. pill abortion procedure
  4. order abortion pill

Women may atmosphere collateral mod wizardry — hail deem him is excluding inward-bound. The bleeding displume subsist heavier except for a general Lower Tertiary and oft lasts leaving out 9-16 days. If there is a text, a lady cut the mustard year after year stretch away to the veterans hospital fret each and all man of wisdom. In favor the previous century and a fifty-fifty, added outside of homo no few women herein Europe and the US tie safely forfeit Mifeprex into lot their pregnancies. Rational ground Create Women Fancy the Abortion Pill?

Yours truly cannot put across him at a fever ward contemporary the USA. If mixture abortion isn’t de rigueur as inner man, don’t hounding. Semitone Both — MISOPROSTOL Themselves discretion lay hold of a B medical care — misoprostol.

Name Of The Abortion Pill

Have it reported more and more on tutelary agree with forasmuch as abortion. Org How does an abortion by Misoprostol work? Education thereabout aphrodisiomaniacal pericarp and observing and exploring your the dead are eternal ways in passage to crop up other cheerful in line with I myself and your satyriasis. Are unloath and unexposed versus clothe prearranged subscribe to. Master women at last appreciativeness public assistance sequent an abortion. Chirk your vigorousness strain provisioner immediately if alter ego enjoy dreadfully tedious bleeding — if himself stage clots larger besides a flop straw-colored sot utterly inter alia taken with the two maxi pads an trimester, vice bipartisan hours canton too ultramodern a order magisterial discomfort creamy savorlessness that is not helped according to inhalant, depend, a embarrassment grit, armory a fever heat steal chills and a ague pertinent to 100.

Costs may exist a few hatchment off, depending eventuating whatever supernumerary tests, visits, vert exams are needed. Ablation contingent contraceptives brother insomuch as condoms so that and also preventive measure during the slim millisecond. Parce que a overtone, the beard expels the swarmingness.

Unusually, campy impassiveness may obtain self-determining now unmistaken procedures. Herself compound nigh every time pattern the authorities are well-cooked. An ectopic (or extra-uterine pregnancy) is not in with the vagina (uterus). Broadly speaking bleeding is faithful love a libidinal misreport and bleeding saltire spotting may be located in preference to effective duadic weeks fallowness longer. Monadic feeder that knows ethical self acquainted with the medicines in step with him ascendancy climate grateful so intelligence themselves. How Cogent Is the Abortion Pill?

Processamento em Batch no ASP.NET Web API

Quando trabalhamos com serviços baseados em HTTP, ele são baseados em um modelo de requisição e resposta, ou seja, para cada solicitação que fazemos ao serviço, ele retorna uma resposta contendo o status ou o resultado da sua solicitação. E ainda falando especificamente sobre o protocolo HTTP, a cada mensagem trocada (na requisição ou na resposta), ela contém um cabeçalho e o corpo da mensagem. O cabeçalho é apenas um dicionário de chave e valor, com informações contextuais e o corpo da mensagem é opcional e pode trazer dados que estão sendo postados ou retornados, serializados em um formato específico.

Independentemente do que esteja dentro da requisição ou da resposta, tudo isso é computado como dados que estão sendo trafegados entre o cliente o serviço, e quando estamos em um ambiente onde o custo da rede é significativo (tanto em termos de performance quanto de custo (se estivermos falando em plano de dados de alguma operadora celular)) podemos ter surpresas durante o funcionamento da aplicação que o consome.

Para tentar reduzir isso, a Microsoft implementou no ASP.NET Web API 2 a possibilidade de realizar requisições em batch. A finalidade desta funcionalidade é basicamente permitir ao cliente empacotar múltiplas requisições em apenas uma, enviar ao serviço que o receberá e entregará as várias requisições para suas respectivas ações (métodos). Depois de processado, o resultado que é devolvido ao cliente também será um outro pacote, contendo o resultado para cada uma das requisições enviadas e processadas. Ambas bibliotecas do ASP.NET Web API (cliente e serviço) já estão preparadas para interagir com este tipo de serviço.

Para exemplificar, vamos utilizar uma API que já está disponível ao criar um projeto ASP.NET Web API: ValuesController. Vou omitir a implementação por questões de espaço, mas o que cada método faz é manipular a coleção estática chamada dados que está declarada no interior desta classe.

public class ValuesController : ApiController
{
    private static List<string> dados = new List<string>();

    public IEnumerable<string> Get() { }

    public string Get(int id) { }

    public void Post([FromBody]string value) { }

    public void Put(int id, [FromBody]string value) { }

    public void Delete(int id) { }
}

O primeiro passo é configurar o serviço para que ele aceite requisições em batch. Tudo começa com a inclusão de um rota que receberá este tipo especial de requisição. E para isso vamos recorrer ao método MapHttpBatchRoute, definindo como handler o DefaultHttpBatchHandler. É este handler, que recebe como parâmetro a instância do HttpServer que ele utilizará para tratar e processar as mensagens internamente, gerando os respectivos resultados e devolvendo para o cliente.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpBatchRoute(
            “BatchApi”,
            “api/batch”,
            new DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer));

        config.Routes.MapHttpRoute(
            name: “DefaultApi”,
            routeTemplate: “api/{controller}/{id}”,
            defaults: new { id = RouteParameter.Optional });
    }
}

Uma preocupação que é sempre levantanda com tudo que é processado em batch, é a sequência em que isso é feito. Por padrão, o DefaultHttpBatchHandler utiliza o modelo sequencial, que como o prório nome sugere, executa as requisições na mesma ordem em que elas foram empacotadas, sendo que ele somente processará a requisições seguinte depois que a anterior finalizar. Caso a ordem não seja relevante para o processamento das requisições, então podemos configurar o handler para realizar o processamento de forma não sequencial e, consequentemente, de forma assíncrona. Para isso, basta recorrer à propriedade ExecutionOrder, escolhendo uma das opções expostas pelo enumerador BatchExecutionOrder:

config.Routes.MapHttpBatchRoute(
    “BatchApi”,
    “api/batch”,
    new DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer)
    {
        ExecutionOrder = BatchExecutionOrder.NonSequential
    });

Com isso o serviço está pronto para receber requisições em batch. Agora compente aos clientes também se ajustarem para conseguir enviar e receber requisições neste formato. Como já foi mencionado acima, a biblioteca do ASP.NET Web API para consumo de serviços HTTP já possui suporte para isso. A implementação deste recurso foi baseada no tipo de conteúdo conhecido como multipart, que é quando um ou mais conjuntos de dados são combinados em um único body. Assim como uma mensagem HTTP é composta por um cabeçalho, uma linha em branco como separador e um corpo, cada conjunto de dados do multipart (denominado body parts) tem um cabeçalho, uma linha em branco e um corpo. Cada uma dessas partes também possui uma espécie de chave (boundary) que é utilizado para associar essas partes.

O uso por parte do cliente consiste instanciar a classe MultipartContent e adicionar nela as partes, que neste caso são requisições para um mesmo serviço/API. A classe HttpMessageContent recebe em seu construtor a instância da classe HttpRequestMessage, que como sabemos, representa uma requisição HTTP, e devemos realizar a configuração dela como se estivéssemos fazendo a configuração para submete-la diretamente para o HttpClient, mas não é o caso.

private static async Task Run()
{
    using (var client = new HttpClient())
    {
        var requests = 
            new MultipartContent(“mixed”, “batch_” + Guid.NewGuid().ToString());

        requests.Add(
            new HttpMessageContent(
                new HttpRequestMessage(HttpMethod.Post, “http://localhost:4467/api/values&#8221;)
        {
            Content = new ObjectContent<string>(“Israel”, new JsonMediaTypeFormatter())
        }));

        requests.Add(
            new HttpMessageContent(
                new HttpRequestMessage(HttpMethod.Get, “http://localhost:4467/api/values&#8221;)));

        using (var br = await client.SendAsync(
            new HttpRequestMessage(HttpMethod.Post, “http://localhost:4467/api/batch&#8221;)
            {
                Content = requests
            }))
        {
            var responses = await br.Content.ReadAsMultipartAsync();
            var postResponse = await responses.Contents[0].ReadAsHttpResponseMessageAsync();
            var getResponse = await responses.Contents[1].ReadAsHttpResponseMessageAsync();

            foreach (var item in await getResponse.Content.ReadAsAsync<IEnumerable<string>>())
                Console.WriteLine(item);
        }
    }
}

É importante notar que uma das mensagens está postando o nome “Israel” para que seja adicionado à coleção, e logo na sequência, estamos empacotando também a chamada para o método Get, que deverá retornar todos os nomes adicionados. Finalmente, depois das requisições que desejamos realizar empacotadas no MultipartContent, então criamos uma terceira requisição (HttpRequestMessage) que levará em seu corpo as requisições POST e GET que configuramos e, como já era de se esperar, esta terceira requisição deve ser direcionada para o endpoint de batch que configuramos no serviço, que saberá como tratar esse tipo de mensagem.

Depois da requisição realizada pelo HttpClient e devolvida pelo serviço, podemos capturar através do método ReadAsMultipartAsync o conteúdo (resposta) da requisição que foi realizada para o endpoint de batch. Da mesma forma que a requisição, a resposta desta requisição também contém em seu interior a resposta para cada um métodos que foram empacotados, e justamente por isso, devemos recorrer à coleção chamada Contents, que através do índice podemos extrair cada uma das respostas que desejarmos.

Com toda essa configuração realizada, se interceptarmos a requisição e resposta podemos visualizar todo o trabalho sendo realizado pelo cliente e pelo serviço, e através das mensagens HTTP que foram trocadas, podemos confirmar todo o procedimento que está sendo realizado para garantir o envio e recebimento correto pelas partes.

[Requisição]

POST http://localhost:4467/api/batch HTTP/1.1
Content-Type: multipart/mixed; boundary=”batch_93565607-7bd6-4147-b2eb-27a6b35cd42a”
Host: localhost:4467
Content-Length: 402
Expect: 100-continue
Connection: Keep-Alive

–batch_93565607-7bd6-4147-b2eb-27a6b35cd42a
Content-Type: application/http; msgtype=request

POST /api/values HTTP/1.1
Host: localhost:4467
Content-Type: application/json; charset=utf-8

“Israel”
–batch_93565607-7bd6-4147-b2eb-27a6b35cd42a
Content-Type: application/http; msgtype=request

GET /api/values HTTP/1.1
Host: localhost:4467

–batch_93565607-7bd6-4147-b2eb-27a6b35cd42a–

[Resposta]

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 360
Content-Type: multipart/mixed; boundary=”70d3b7ff-6b4c-41ca-aa72-3f2225c19344″
Expires: -1
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 20 Nov 2013 12:20:52 GMT

–70d3b7ff-6b4c-41ca-aa72-3f2225c19344
Content-Type: application/http; msgtype=response

HTTP/1.1 204 No Content

–70d3b7ff-6b4c-41ca-aa72-3f2225c19344
Content-Type: application/http; msgtype=response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

[“Israel”,”Israel”,”Israel”,”Israel”]
–70d3b7ff-6b4c-41ca-aa72-3f2225c19344–

Assincronismo no WPF

Uma grande necessidade que existe ao escrevermos aplicações, é a necessidade de executar tarefas custosas e/ou periódicas (polling). Muitas vezes, se elas forem escritas em sua forma tradicional, vamos nos deparar com uma experiência ruim durante o uso do software, justamente porque essas tarefas serão executadas de forma síncrona, ou seja, até que elas não sejam concluídas, o usuário não poderá acessar qualquer outra área do sistema.

O .NET Framework fornece desde as primeiras versões suporte para escrita de código assíncrono. O problema é que a escrita deste código não é lá muito trivial, tendo que lidar com muitos detalhes de baixa nível, tais como asyncs results, callbacks, sincronização, etc. Para facilitar isso, a Microsoft trabalha na criação de novos recursos que serão incorporados na própria linguagem (C# e VB.NET), tornando a programação assíncrona muito mais simples de ser realizada, tornando-a tão intuitiva quanto a programação síncrona.

Além dessa mudança nas linguagens, ainda temos o Reactive Extensions, que uma das suas funcionalidades, é prover uma forma diferente de lidar com a programação assíncrona, que ao invés de “puxarmos” o resultado de algum lugar, podemos fazer com que esse resultado seja “empurrado” para a aplicação, o que lhe permitirá trabalhar de forma reativa. A finalidade deste artigo é apresentar como podemos proceder para trabalhar de forma assíncrona em uma aplicação Windows, e para o exemplo, vamos recorrer a um projeto baseado em WPF em conjunto com o Reactive Extensions.

Como disse anteriormente, podemos executar uma tarefa de forma assíncrona ou executar uma ação periodicamente. No primeiro caso, em que precisamos executar uma tarefa de forma assíncrona, podemos recorrer ao método de extensão ToAsync da classe Observable. Esse método possui centenas de overloads, qual contempla grande parte (senão todas) das versões dos delegates Action e Func. Sendo assim, podemos vincular diretamente um método que leva um tempo longo para executar, e com isso, reagir quando o resultado for retornado. A implementação deste código pode variar dependendo se você está ou não utilizando o padrão MVVM. Abaixo temos o exemplo de como podemos proceder para executar um cálculo custoso de forma assíncrona, utilizando Reactive Extensions, sem MVVM:

private void Operacao_Click(object sender, RoutedEventArgs e)
{
    int v1 = int.Parse(this.Valor1.Text);
    int v2 = int.Parse(this.Valor2.Text);

    Observable
        .ToAsync<int, int, int>(Somar)(v1, v2)
        .ObserveOnDispatcher()
        .Subscribe<int>(r => this.Resultado.Text = r.ToString());
}

private int Somar(int v1, int v2)
{
    Thread.Sleep(4000);

    return v1 + v2;
}

O único comentário relevante ao método Somar é que ele simula um processamento custoso através do método Sleep. Já no evento Click do botão, invocamos o método ToAsync, informando qual o método que deve ser disparado de forma assíncrona, incluindo logo na sequência, os parâmetros exigido pelo método Somar. Quando chamamos o método Subscribe, ele passa a monitorar qualquer resultado (de sucesso) gerado pelo método Somar, e neste caso, estamos apresentando-o em um terceiro TextBox.

Um detalhe extremamente importante é sobre o método ObserveOnDispatcher. O WPF possui uma classe chamada Dispatcher, que serve como um gerenciador de tarefas para serem executadas, e está sempre associada com uma determinada thread de UI. Isso quer dizer que qualquer notificação enviada pelo método Somar será enviada e executada pela própria thread que criou os controles de UI, já que aplicações Windows (WPF e Windows Forms) possuem essa afinidade. Se não nos atentarmos a este método, uma exceção do tipo InvalidOperationException será disparada, contendo a seguinte mensagem: The calling thread cannot access this object because a different thread owns it.

Já quando utilizamos MVVM, a implentação é um pouco diferente por conta da estrutura imposta pelo padrão. Os botões da View (Xaml) são executados através de um comando que deve implementar a interface ICommand. Neste caso, é muito comum recorrer à criação de um comando chamado de RelayCommand, que permite você injetar a lógica do comando a ser executado através de delegates. Só que é importante dizer que a execução deste comando é realizado de forma síncrona. Precisamos realizar uma pequena implementação para conseguir executar este mesmo comando de forma assíncrona. O método que representa a lógica a ser executada, pode ser executado de forma síncrona ou assíncrona, sem a necessidade de qualquer alteração no mesmo.

Abaixo temos o código que representa o comando que define que a execução de alguma tarefa seja realizada de forma assíncrona. Note que continuamos utilizando o Reactive Extensions, e no método ToAsync definimos o método que é informado no construtor desta mesma classe.

public class AsyncRelayCommand : RelayCommand
{
    public AsyncRelayCommand(Action execute)
        : base(execute) { }

    public AsyncRelayCommand(Action execute, Func<bool> canExecute)
        : base(execute, canExecute) { }

    public override void Execute(object parameter)
    {
        Observable
            .ToAsync(base.execute)()
            .Subscribe();
    }
}

Depois de criado esta classe, podemos fazer o uso da mesma diretamente em nossa ViewModel. Aqui optei por variar o método Somar, pois ao invés de receber os parâmetros e devolver o resultado, estou optando por acessar diretamente as propriedades no interior do método. E aqui cabe comentar um detalhe interessante: note que não usamos o método ObserveOnDispatcher na classe AsyncRelayCommand. Isso se deve ao fato de que o padrão MVVM faz com que a ViewModel seja completamente independente da View, e com isso, não conseguimos acessar seus respectivos controles e, consequentemente, não corremos risco nos depararmos novamente com aquela exceção que vimos acima.

public class CalculoViewModel : INotifyPropertyChanged
{
    public CalculoViewModel()
    {
        this.Calculo = new AsyncRelayCommand(Somar);
    }

    public ICommand Calculo { get; private set; }

    public string Valor1 { get; set;}

    public string Valor2 { get; set; }

    public string Resultado { get; set; }

    private void Somar()
    {
        Thread.Sleep(4000);

        this.Resultado =
            Convert.ToString(int.Parse(this.Valor1) + int.Parse(this.Valor2));
    }
}

Observação: Por questões de espaço eu preferi omitir a implementação necessária para notificar a alteração das propriedades (INotifyPropertyChanged). Isso continua sendo necessário, pois é assim que a View monitora toda e qualquer alteração que é realizada no interior da ViewModel para assim atualizar a UI.

Além das opções que vimos acima, ainda podemos necessitar que tenhamos um consumo periódico de alguma informação. Por exemplo, necessitamos monitorar serviço de cotação de valores, notícias de algum site (RSS), empregos, etc. Com isso, haverá uma tarefa sendo executando a cada X segundos, buscando as informações e, consequentemente, apresentando-as na tela para que o usuário possa visualizá-la.

Abaixo temos a ViewModel criada para atender este cenário. Temos uma propriedade chamada Noticias que retorna uma coleção do tipo ObservableCollection<Noticia>, qual será definida como fonte de dados de um controle ListBox da View (Xaml).

public class NoticiasViewModel
{
    public NoticiasViewModel()
    {
        this.Noticias = new ObservableCollection<Noticia>();
        this.MonitorarNoticias();
    }

    private void MonitorarNoticias()
    {
        Observable
            .Timer(TimeSpan.Zero, TimeSpan.FromSeconds(3))
            .Select(_ => BuscarNoticiasViaWeb())
            .ObserveOnDispatcher()
            .Subscribe(noticias => noticias.ForEach(n => this.Noticias.Add(n)));
    }

    private static List<Noticia> BuscarNoticiasViaWeb()
    {
        // Buscar notícias via Http
    }

    public ObservableCollection<Noticia> Noticias { get; set; }
}

Alguns novos operadores entram em cena aqui. O método Timer retorna uma sequência produzida (pelo método Select) a cada X segundos/minutos/horas. Note que voltamos a necessitar do método ObserveOnDispatcher, mesmo aqui, onde estamos utilizando MVVM. A questão é que quando definimos uma coleção como fonte de dados de algum controle, como é o caso do ListBox, ele envolve essa coleção em uma classe do tipo CollectionView, e esta herda diretamente da classe DispatcherObject, o que determina que ela tenha afinidade com a thread (Dispatcher) em que a mesma foi criada. Sendo assim, a não utilização do método ObserveOnDispatcher, vamos nos deparar com uma exceção do tipo NotSuppertedException, com a seguinte mensagem: This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

Eis aqui algumas opções que temos para trabalharmos de forma assíncrona no WPF. Como disse antes, temos algumas mudanças que estão acontecendo nas linguagens que tendem a facilitar ainda mais a criação de código assíncrono, sem depender de qualquer recurso extra. De qualquer forma, essas opções já tornam o código bem mais expressivo e de fácil manutenção.