Programming Languages Hacks

Importanti regole per linguaggi di programmazione rilevanti come Java, C, C++, C#…

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

Convert Event-Based Asynchronous to Task

Posted by Ricibald on 29th November 2015

Convert Event-Based Asynchronous to Task

The following example shows how to expose an arbitrary sequence of Event-Based Asynchronous Pattern (EAP) operations as one task by using a TaskCompletionSource<TResult>.

The example also shows how to use a CancellationToken to invoke the built-in cancellation methods.

When to use it:

  • you have a mix of Events and Tasks and you need to uniform them
  • you have an Event that needs to be treated using your already-done Task background processing
  • you have a complex flow of Events and you need to simplify the code readability

This extension method do the work:

public static class TaskExt
{
    public static async Task<TEventArgs> FromEvent<TEventArgs>(
        Action<EventHandler<TEventArgs>> registerEvent,
        Action action,
        Action<EventHandler<TEventArgs>> unregisterEvent,
        CancellationToken token)
    {
        var tcs = new TaskCompletionSource<TEventArgs>();
        EventHandler<TEventArgs> handler = (sender, args) => tcs.TrySetResult(args);
        registerEvent(handler);

        try 
        {
            using (token.Register(() => tcs.SetCanceled()))
            {
                action();
                return await tcs.Task;
            }
        }
        finally
        {
            unregisterEvent(handler);
        }   
    }
}

So if you have this class with this event:

public class LdapProvider {
    public event EventHandler<string> Authenticated;
    public void Authenticate(string username, string password) {
        // show the browser...
    }
    //... called back from the browser
    public void AuthenticateCallback(string token) {
        if(Autenticated != null)
            Authenticated(token);
    }
}

You can call this class using events in this way:

// save Token from ldapProvider when the event Autenticate fires
var ldapProvider = new LdapProvider();
ldapProvider.Authenticate("username", "password");
ldapProvider.Authenticated += (sender, token) => this.Token = ldapProvider.Token;
// wait for event be fired...

It can be converted in this way:

public static class LdapProviderExtensions {
    public static async Task<string> AuthenticateAsync(this LdapProvider ldapProvider, string username, string password) { 
        await TaskEx.FromEvent<string> (
            handler => ldapProvider.Authenticated += new EventHandler<string> (handler), 
            () => ldapProvider.Authenticate("username", "password"),
            handler => ldapProvider.Authenticated -= new EventHandler<string> (handler),
            CancellationToken.None);
    }
}


And used in this simple way:

// save Token from ldapProvider when the event Autenticate fires
var ldapProvider = new LdapProvider();
var token = await ldapProvider.AuthenticateAsync("username", "password");
// you have the token without saving it in a property...

Posted in .net | 1 Comment »

.NET: convertire due tipi generici

Posted by Ricibald on 4th November 2014

Come convertire in modo generico un tipo in un altro tipo?

Immaginiamo di dover convertire un tipo generico MyCustomType in un altro tipo (es. string). Ci sono diversi modi: dal semplice ToString() a un cast verso string. Finche si converte da MyCustomType verso string non è un problema, ma quando si procede al contrario questo non è possibile poiché string è fuori dal nostro controllo.

Per queste casistiche esiste da .NET 2.0 l’attributo TypeConverter da dichiarare all’interno di MyCustomType:

[TypeConverter(typeof(MyCustomTypeConverter))]
 public class MyCustomType {
    private string Data { get; set; }
    public static MyCustomType Parse(string data) {
        // convert code from string to MyCustomType here...
        return new MyCustomType { Data = data };
    }
    public override ToString() {
        // convert code from MyCustomType to string here...
        return this.Data;
    }
 }

public class MyCustomTypeConverter : TypeConverter {
    public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(string) || base.CanConvertTo (context, destinationType);
    }

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value is string)
            return MyCustomType.Parse ((string)value);  // YOUR CONVERT HERE

        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        var myCustomTypeToConvert = (MyCustomType)value;
        if (destinationType == typeof(string))
            return myCustomTypeToConvert.ToString ();   // YOUR CONVERT HERE

        return base.ConvertTo (context, culture, value, destinationType);
    }
}

Una volta costruito il converter si invoca nel seguente modo per convertire da/a un certo tipo:

MyCustomType myCustomType = new MyCustomType { Data = "MyData" };
TypeConverter myCustomTypeConverter = TypeDescriptor.GetConverter (typeof(MyCustomType));

string myCustomTypeAsText = (string) myCustomTypeConverter.ConvertTo(myCustomType, typeof(string));
MyCustomType myCustomTypeFromText = (MyCustomType) myCustomTypeConverter.ConvertFrom("MyData2");

Questo risolve il problema finquando sappiamo quale dei due tipi implementa il TypeConverter per quella particolare conversione, cosa che potremmo non sapere in una gestione completamente generica.

Per questo motivo ho implementato il seguente extension method che consente di convertire due tipi generici andando a inferire in automatico quale TypeConverter utilizzare:

/// <summary>
/// Converte l'istanza. Usa il TypeDescriptor di T
/// </summary>
public static TDestination ConvertSafe<TDestination>(this object value) {
    if (value == null)
        return default(TDestination);

    // se sono gia lo stesso tipo non fare nulla
    if (typeof(TDestination) == value.GetType ())
        return (TDestination)value;

    // prova a convertire usando il converter di T
    var targetConverter = TypeDescriptor.GetConverter (typeof(TDestination));
    if(targetConverter != null && targetConverter.CanConvertFrom(value.GetType())) 
        return (TDestination)targetConverter.ConvertFrom (value);

    // prova a convertire usando il converter di value
    var sourceConverter = TypeDescriptor.GetConverter (value);
    if(sourceConverter != null && sourceConverter.CanConvertTo(typeof(TDestination))) 
        return (TDestination)sourceConverter.ConvertTo (value, typeof(TDestination));

    throw new InvalidCastException (String.Format("Unable to convert {0} to {1}", value.GetType(), typeof(TDestination)));
}

Esempio di utilizzo:

MyCustomType myCustomType = "MyData".ConvertSafe<MyCustomType>();
string myCustomTypeAsText = myCustomType.ConvertSafe<string>();

Che abilita scenari come il seguente che converte un tipo string (in teoria non convertibile) in un generico tipo MetaData<T> sfruttando internamente il TypeConverter del tipo T determinato a tempo di compilazione:

public MetaData<T> GetMetaInfo<T>(string value) {
    var result = new MetaData<T>(value.ConvertSafe<T>());
    return result;
}

Posted in .net | No Comments »

Adapt/convert Microsoft Ajax events to JQuery

Posted by Ricibald on 22nd July 2011

It’s very useful to express everything in JQuery instead of ASP.NET AJAX events system: in this way we can use a lot of useful JQuery controls.

To achieve this just add this snippet of javascript code:

<script type="text/javascript">
	Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequest);
	Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequest);
	function BeginRequest(sender, args) {
		jQuery.event.trigger('ajaxSend');		
	}
	function EndRequest(sender, args) {   
		jQuery.event.trigger('ajaxComplete');		                             
	}
</script>

In this way you can capture standard JQuery event to obtain for example a modal progress feedback both in case of JQuery ajax POST and in case of ASP.NET UpdatePanel events:

<script type="text/javascript">
	$(document).bind("ajaxSend", function () {
		$("#loadingAjax").dialog({ modal: true });
	}).bind("ajaxComplete", function () {
		$("#loadingAjax").dialog("close");
	});
</script>

Posted in asp.net, javascript, jQuery | No Comments »