Fujiy

Blog sobre .NET, C#, ASP.NET entre outras tecnologias de desenvolvimento de software

A diferença que o C# 5.0 faz com o async/await

11/03/2013 20:51:02 Por Fujiy

A melhor forma de ver a grande diferença que o async faz é usando exemplos. Saindo de um código não só maior, mas muito mais complicado, com callbacks, tratamento de contexto e thread de execução, tratamento de erros aninhados com os callbacks, pra um código simples, como se fosse um código síncrono comum.

Código Antigo:

void ShowStuff()
{
    var client = new WebClient();
    var content = JsonValue.Parse(client.DownloadString("http://api.worldbank.org/countries?format=json&per_page=50"));
    int number_of_countries = content[0]["total"];
    int done = 0, error = 0;
 
    InvokeOnMainThread(() =>
    {
        CountriesLabel.Text = string.Format("Countries: {0} done: 0 error: 0", number_of_countries);
    });
 
    foreach (JsonObject c in content[1])
    {
        string country_url = string.Format("http://api.worldbank.org/countries/{0}/indicators/NY.GDP.MKTP.CD&format=json", (string)c["id"]);
        JsonValue json = null;
 
        try
        {
            json = JsonValue.Parse(client.DownloadString(country_url));
        }
        catch (Exception e)
        {
            ++error;
            InvokeOnMainThread(() => status.Text = "Got exception " + e);
            continue;
        }
 
        ThreadPool.QueueUserWorkItem(delegate
        {
            Map map = null;
            try
            {
                map = LoadCountryLogo(c["name"]).Result;
            }
            catch (Exception e)
            {
                ++error;
                InvokeOnMainThread(() => status.Text = "Got exception " + e);
            }
            if (map != null)
            {
                ThreadPool.QueueUserWorkItem(delegate
                {
                    Position position = null;
 
                    try
                    {
                        position = LookupCountryPosition(c["longitude"], c["latitude"]).Result;
                        if (position != null)
                            InvokeOnMainThread(() =>
                            {
                                AddPin(map, position);
                                ++done;
                                status.Text = json["name"];
 
                            });
                    }
                    catch (Exception e)
                    {
                        error++;
                        InvokeOnMainThread(() => status.Text = "Got exception " + e);
                    }
 
                });
            }
        });
 
        InvokeOnMainThread(() => CountriesLabel.Text = string.Format("Countries: {0} done: {1} error: {2}", number_of_countries, done, error));
    }
    InvokeOnMainThread(() =>
    {
        CountriesLabel.Text = string.Format("Countries: {0}", number_of_countries);
    });
}

Código usando C# 5.0:

async Task ShowStuffAsync()
{
    var client = new HttpClient();
 
    var content = JsonValue.Parse(await client.GetStringAsync("http://api.worldbank.org/countries?format=json"));
    int number_of_countries = content[0]["per_page"];
    int done = 0, error = 0;
 
    CountriesLabel.Text = string.Format("Countries: {0} done: 0 error: 0", number_of_countries);
 
    foreach (JsonObject c in content[1])
    {
        try
        {
            string country_url = string.Format("http://api.worldbank.org/countries/{0}/indicators/NY.GDP.MKTP.CD&format=json", (string)c["id"]);
            var json = JsonValue.Parse(await client.GetStringAsync(country_url));
            var map = await LoadCountryLogoAsync(json["name"]);
            if (map != null)
            {
                var position = await LookupCountryPositionAsync(c["longitude"], c["latitude"]);
                if (position != null)
                {
                    AddPin(map, position);
                    status.Text = json["name"];
                    ++done;
                }
            }
 
        }
        catch (Exception e)
        {
            ++error;
            status.Text = "Got exception " + e;
        }
        CountriesLabel.Text = string.Format("Countries: {0} done: {1} error: {2}", number_of_countries, done, error);
    }
    CountriesLabel.Text = string.Format("Countries: {0}", number_of_countries);
}

 

Unobtrusive jQuery Validation com forms dinâmicos

05/03/2013 21:53:00 Por Fujiy

Recentemente tive um problema ao usar um form dinâmico no ASP.NET MVC. A validação não "intrusiva" é processada assim que a página termina de carregar, e a partir daquele momento não é mais alterada. Porém eu tinha uma página que carregava todo o conteúdo do form via Ajax, e neste caso é ainda pior do que carregar um novo form, pois se o form já existia ele é marcado para não ser processado novamente, então preciso primeiro desmarca-lo e depois ativar a validação novamente. O código é simples, só não é algo suportado ou documentado, e depende de detalhes da implementação atual:

var form = $('#form-adiciona-entrega');

form.removeData('validator').removeData('unobtrusiveValidation');//Este passo só é necessário se o form já existia. Se o form em si é gerado dinamicamente, não precisa desse "reset"

$.validator.unobtrusive.parse(form);

 

Encontrei também este código, que diz fazer isso automaticamente a cada chamada ajax, mas que depende também de detalhes do ASP.NET MVC:

$(document).ajaxSuccess(function (event, xhr, settings) {
   if (settings.mvcTargetElement) {
       $(settings.mvcTargetElement.getAttribute("data-ajax-update")).each(function () {
          $.validator.unobtrusive.parse(this);
     });
  }
});

 

 

Fontes:

http://btburnett.com/2011/01/mvc-3-unobtrusive-ajax-improvements.html

http://stackoverflow.com/questions/11045256/jquery-client-side-validate-not-working

ASP.NET MVC, usando Array, List, IEnumerable no ViewModel e ModelBind

16/11/2012 19:44:00 Por Fujiy

Um problema comum que sempre me fazia perder um bom tempo e deixava o código um pouco mais sujo era trabalhar com Arrays ou melhor, IEnumerable's em geral. Normalmente tenho um IEnumerable<AlgumaCoisa> no meu ViewModel e quero usar todas as funcionalidades do ASP.NET MVC normalmente com o Model Binding.

Assumindo o seguinte ViewModel:

public class PredioViewModel
{
    public string Nome { getset; }
    public List<AndarViewModel> Andares { getset; }
}
public class AndarViewModel
{
    public int Id { getset;}
    public string Nome { getset; }
    public decimal Preco { getset; }
}

Leia mais...

Criando NuGet Packages - Parte 2 - Package Explorer

16/11/2012 18:09:00 Por Fujiy

Agora que sabemos as convenções usadas podemos criar o package nos padrões recomendados. A forma mais fácil e rápida é usando o Nuget Package Explorer, uma GUI que cria o arquivo .nuspec e o package(.nupkg) de forma visual. Também é possível criar o package manualmente.

Leia mais...

ASP.NET MVC Windows Authentication redirecionando pro login

25/09/2012 22:29:23 Por Fujiy

Esse problema aconteceu em um novo projeto que estou trabalhando na Athié, em ASP.NET MVC 4, mas deve acontecer no 3 também, já que acredito ser um problema no WebPages utilizado pelo Razor. Não sei exatamente o motivo, mas o WebPages sobrescreve algumas configurações de Membership para "facilitar" o uso do WebMatrix. Não concordo com a decisão já que o produto principal não é o WebMatrix. De qualquer forma, o problema é o seguinte, já configurei o web.config pra usar Windows Authentication, com e sem impersonate e o primeiro request sempre redirecionava para a url de login que no caso não existe e dá erro 404. Pensei ser um problema do Chrome, mas também acontecia com o Firefox, exceto com o Internet Explorer.

Para solucionar o problema é preciso colocar essa chave no appSettings:

<add key="enableSimpleMembership" value="false"/>

Voltando o Membership ao padrão em vez de sobrescrever pelo Membership do WebPages.

É estranho que o ASP.NET MVC 3 e 4 vem com templates de Intranet e os mesmos não incluem essa chave.

UPDATE: A raiz do problema está na presença da dll WebMatrix.Data.dll. No meu caso ela estava presente pois o projeto foi criado com o template Internet e depois alterado pra Windows Authentication. Removendo essa dll não precisa da chave no web.config