Fujiy

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

.NET Transactional File Manager

01/10/2013 21:00:00 Por Fujiy

Estamos acostumados a usar transações sempre que trabalhamos com banco de dados, mesmo pra quem usa um ORM como o Entity Framework, que cria as transações implicitamente. Isso tudo pra garantir que nossas alterações sejam atomicas, evitando pedidos de compra sem itens, um débito sem um crédito, um pagamento de salário sem marcá-lo como pago, etc.

Esse processo fica mais complicado quando temos arquivos em disco envolvidos, por exemplo, um processo onde se insere uma linha no banco e move um arquivo, principalmente dentro de um laço. Se ocorrer uma exception de disco cheio no 10º arquivo, como fazer pra voltar os 9 anteriores ao local original? Tratar manualmente não parece muito confiável e limpo.

Pra estes casos existe uma biblioteca chamada .NET Transactional File Manager, é bem simples e funciona praticamente sem overhead, implementando a interface IEnlistmentNotification, permitindo participar de uma transação do System.Transactions.Transaction.

A biblioteca não usa o Transactional NTFS, o que permite o uso no Windows XP e Windows Server 2003, por isso também não faz uso do DTC.

Então a biblioteca não é confiavel? Depende! Da maneira que ela funciona não vai garantir o Rollback em caso de falha de hardware ou se o processo for finalizado, ela funciona automatizando o que teriamos que tratar manualmente se a transação for cancelada, movendo de volta os arquivos, apagando o que foi copiado ou criado, etc. No meu caso é o suficiente. Se for necessário usar Transactional NTFS existe a biblioteca AlphaFS.

A utilização é muito simples, parecido com a classe File, só não é static, não sei o motivo.

new TxFileManager().Move(fonte, destino);

.NET Transactional File Manager no Codeplex

.NET Transactional File Manager no NuGet

InstaSharp - Biblioteca C# que encapsula a API do Instagram

26/09/2013 20:23:12 Por Fujiy

O InstaSharp é uma biblioteca C# que encapsula a API do Instagram, uma API RESTful.

Comecei a usar o InstaSharp para um projeto pessoal, mas percebi que faltava algumas propriedades e resolvi criar um fork do código original. Já existia um branch "re-design"com algumas novidades então trabalhei em cima dele e fiz diversas melhorias, principalmente uma atualização de tecnologia.

O projeto original estava meio parado, então o criador da biblioteca me incluiu como colaborador. Acredito que hoje sou o principal e único desenvolvedor ativo no projeto.

Re-escrevi boa parte do código que agora é todo assíncrono. As principais novidades são:

  • Convertido para Portable Class Library
  • Uso o HttpClient em vez do RestSharp
  • Todas chamadas são async
  • Projeto separado para Testes
  • Suporte para .NET 4, .NET 4.5, Silverlight 5, Windows Phone 8 e Windows Store 8

Você também pode criar um fork e contribuir com pull's requests.

Links:

InstaSharp

InstaSharp no GitHub

Meu Fork do InstaShap

Visual Studio 2013 & TFS 2013 RC disponíveis

09/09/2013 15:08:19 Por Fujiy

Ontem instalei o Beta 1 do Visual Studio 2013, cansado de esperar um Release Candidate, e hoje recebo a notícia....hoje saiu o RC1, felizmente pra instalar o RC1 nem precisa desinstalar o Beta 1.

Assim como o Beta, ele vem com licença go-live, o que permite o uso em produção. Esta é uma versão mais próxima à final, com diversas correções, além disso também inclui o TypeScript 0.9.1.1.

O lançamento foi publicado em diversos blogs, onde você pode conferir mais informações e datalhes:

Visual Studio ALM + Team Foundation Server Blog

The Visual Studio Blog

.NET Framework Blog

.NET Web Development and Tools Blog

Brian Harry’s blog

 

Download Visual Studio 2013 RC1 (incluindo a opção por ISO)

TypeScript 0.9.0

18/06/2013 23:08:00 Por Fujiy

Após algum tempo em Alpha e Beta, temos a versão 0.9.0. Pra quem ainda não conhece, o TypeScript é um superset do JavaScript desenvolvido pelo Anders Hejlsberg, pai do C#, que adicionar tipos opcionais e orientação a objetos. Assim todo código JavaScript é um código TypeScript válido. O objetivo é ajudar o desenvolvimento de aplicações em grande escala em JavaScript.

Essa nova versão traz diversas melhorias solicitadas pela comunidade, sendo a principal o suporte a Generics. Além disso o compilador foi reestruturado para lidar com aplicações com centenas de milhares de linha de código.

É fácil começar a usar, uma vez que seu código JavaScript é também TypeScript. Por ser Open Source, existem diversos editores, incluindo o plug-in pra Visual Studio, também recomendo usar em conjunto com a extensão Web Essentials, assim sempre que você salvar um arquivo (.ts) ele já chama o compilador e gera o (.js).

Também é possível usar arquivos de cabeçalho, tipando bibliotecas existentes como o jQuery, Knockout, underscore, etc

Download

Web Essentials

Projeto DefinitelyTyped (Arquivos de Cabeçalho)

Links:

Anúncio v0.9.0

Site Oficial

TypeScript no Codeplex

Try It

Blog

Twitter

 

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);
}