asp.net comments edit

Ormai è appurato che sono un fanatico dei DTO (ne ho parlato qui e qui), ma voglio ugualmente segnalare questo articolo di Pablo M. Cibraro che spiega il perchè non debba essere mai esposta direttamente una classe di EntityFramework, bensì un DTO.
Riporto di seguito una frase che mi ha colpito particolarmente:

I do not know what the folks in Microsoft were thinking when they decided to enable a feature like this. They made a good work teaching us about how evil Datasets were for interoperability with other platforms, and now they came up with a solution like this, no way.

Sempre nello stesso post Pablo forza la mano sul DTO, consiglia AutoMapper e successivamente, in un’altro post, parla della nuova versione di EntityFramework 4.0, dell’implementazione POCO e di RIA Application, spiegando che, nonostante la prossima versione dell’O/RM permetta di decorare le classi con gli attributi DataContract e DataMember, questo tipo di approccio rimane sconsigliato.
Di fatto, un forte accoppiamento tra persistenza, contract e client è particolarmente pericoloso per il versioning del servizio; basti pensare che una entity di dominio può cambiare per qualsiasi motivo, ed in questo caso potrebbe essere necessario modificare il contract ed eventuali clients.
A detta di Pablo, un approccio del genere può risultare comodo unicamente per le RIA Applications, che ad oggi occupano solo una piccolissima parte delle applicazioni services oriented.

Ciauz

various comments edit

Non so da quanto tempo esista, ma è ormai almeno un mese che lo sto utilizzando in un progetto e devo dire che è veramente comodo e ben fatto.
L’idea di potersi avvalere di Linq per effettuare query e manipolazioni di dati su diversi repository, che siano questi database, CSV o oggetti in memoria, è a dir poco fantastica.

L’utilizzo è semplicissimo, basta decorare con gli appositi attributi la classe, specificare come si vuole utilizzare il CSV, se in scrittura o in lettura, e, in quest’ultimo caso, è possibile eseguire la query Linq.

Lo Snippet seguente mostra un’implementazione in lettura.

CsvFileDescription inputFileDescription = new CsvFileDescription
{
    SeparatorChar = ';',
    FirstLineHasColumnNames = true,
    FileCultureName = "it-It"
};

CsvContext cc = new CsvContext();

IEnumerable<PersonCSV> CsvPeople = cc.Read<PersonCSV>(@"C:\Temp\mytestFile.csv", inputFileDescription);

foreach (PersonCSV p in CsvPeople)
{
    //TO DO SOMETHING
}

public class PersonCSV
{
    [CsvColumn(Name = "Nome", FieldIndex = 1, CanBeNull = false)]
    public string FirstName { get; set; }

    [CsvColumn(Name = "Cognome", FieldIndex = 2, CanBeNull = false)]
    public string LastName { get; set; }

    [CsvColumn(Name = "NickName", FieldIndex = 3, CanBeNull=true)]
    public string Nickname { get; set; }
}

Ulteriori informazioni le trovate qui.

.net comments edit

Una combinazione a dir poco snervante per lo sviluppatore, che si trova a subire dei rallentamenti in fase di debug delle proprie pagine web.

Ogni richiesta effettuata dal client verso il web server integrato in Visual Studio richiede un tempo che può arrivare fino ad un secondo per ogni elemento contenuto nella pagina e, considerando che in media una pagina ha circa 50 richieste verso il server, tra immagini, css, javascript, ecc., il tempo può salire fino a circa un minuto, e può andare ben oltre se si hanno pagine particolarmente ricche di contenuti e/o complesse.

Così ieri sera mi son deciso a “sbingare” (cercare con bing.com :-) ) un po’, e sono stato felice di apprendere che non sono l’unico ad avere questo tipo di problema, che sembra essere legato all’IPv6.
Infatti sono risalito a questo post che spiega come risolvere l'inconveniente, disabilitando l’IPv6 sul browser.

Entrando nello specifico basta digitare in Firefox “about:config” –> “network.dns.disableIPv6” doppio click in modo che il valore passi da false a true.

Ovviamente a fine procedura è necessario il riavvio del browser.

Ciauz

.net comments edit

Dopo il post precedente, in cui ho descritto l’utilizzo di AOP in un servizio WCF, ho ricevuto delle richieste relativamente al modo in cui ho realizzato questo tipo di implementazione.
Di seguito potete trovare il codice necessario alla realizzazione di un Custom Behavior per WCF che instanzi un proxy AOP in sostituzione al servizio WCF, e la rispettiva configurazione per utilizzarlo ed aggiungergli Interceptor.
Per ovvi motivi non posso postare il codice che ha permesso l’invalidazione della cache, ma la creazione di un Interceptor simile è veramente banale.

public class AOPInstanceServiceElement : BehaviorExtensionElement
{
    protected override object CreateBehavior()
    {
        return new AOPInstanceServiceBehavior();
    }

    public override Type BehaviorType
    {
        get
        {
            return typeof(AOPInstanceServiceBehavior);
        }
    }
}

public class AOPInstanceServiceBehavior : IServiceBehavior
{
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
        {
            ChannelDispatcher cd = cdb as ChannelDispatcher;
            if (cd != null)
            {
                foreach (EndpointDispatcher ed in cd.Endpoints)
                {
                    ed.DispatchRuntime.InstanceProvider = new AOPInstanceProvider(serviceDescription.ServiceType);
                }
            }
        }
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection&lt;ServiceEndpoint&gt; endpoints, BindingParameterCollection bindingParameters)
    {
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
}

public class AOPInstanceProvider : IInstanceProvider
{
    private readonly Type serviceType;

    public AOPInstanceProvider(Type serviceType)
    {
        this.serviceType = serviceType;
    }

    public object GetInstance(InstanceContext instanceContext)
    {
        return GetInstance(instanceContext, null);
    }

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        IApplicationContext context = ContextRegistry.GetContext();

        string proxyName = serviceType.FullName;
        if (!context.ContainsObject(proxyName))
            throw new ArgumentException(string.Format(&quot;There must exist exactly one &lt;object&gt; definition for the {0} service in the Spring configuration&quot;, serviceType.Name));

        return context.GetObject(proxyName);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        if (instance is IDisposable)
        {
            ((IDisposable)instance).Dispose();
        }
    }
}


public class MyLogAdvice : IMethodInterceptor
{
    public object Invoke(IMethodInvocation invocation)
    {
        string className = invocation.TargetType.FullName;

        Logger.Info(className, string.Format("Start Method : {0}", invocation.Method.Name));

        object result = invocation.Proceed();

        Logger.Info(className, string.Format("End Method : {0}", invocation.Method.Name));

        return result;
    }
}

Configurazione del servizio:

<spring>
    <context>
        <resource uri="config://spring/objects" />
    </context>
    <objects xmlns="http://www.springframework.net">
        <object id="logAdvice" type="CommunityDays.WCF.AOP.LogAdvice.MyLogAdvice, CommunityDays.WCF.AOP.LogAdvice" />
        <object id="rewardingAdvice" type="CommunityDays.WCF.AOP.RewardingAdvice.MyRewardingAdvice, CommunityDays.WCF.AOP.RewardingAdvice" />
        <object id="CommunityDays.WCF.AOP.Service.Service1" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
            <property name="Target">
                <ref object="Service1AOP" />
            </property>
            <property name="InterceptorNames">
                <list>
                    <value>logAdvice</value>
                </list>
            </property>
        </object>
        <object id="Service1AOP" type="CommunityDays.WCF.AOP.Service.Service1, CommunityDays.WCF.AOP.Service" />
    </objects>
</spring>

<system.serviceModel>
    
    <extensions>
        <behaviorExtensions>
            <!-- ocio a non togliere mai gli spazi dopo le , - usare sempre anche il version number - è un bug di WCF -->
            <add name="aopInstanceBehavior" type="CommunityDays.WCF.AOP.Services.Behaviors.AOPInstanceServiceElement, CommunityDays.WCF.AOP.Services.Behaviors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </behaviorExtensions>
    </extensions>

    <services>
        <service name="CommunityDays.WCF.AOP.Service.Service1" behaviorConfiguration="MyServiceConfiguration">
            <host>
                <baseAddresses>
                    <add baseAddress="net.pipe://localhost/Service1"/>
                    <add baseAddress="net.tcp://localhost:7002" />
                </baseAddresses>
            </host>
            <endpoint address="Service1" binding="netTcpBinding" contract="CommunityDays.WCF.AOP.Contracts.IService1" />
            <endpoint binding="netNamedPipeBinding" bindingConfiguration="MyNamedPipeBinding" contract="CommunityDays.WCF.AOP.Contracts.IService1" />
            <endpoint address="Service1/mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
        </service>
    </services>

    <bindings>
        <netNamedPipeBinding>
            <binding name="MyNamedPipeBinding" >
                <security mode="None">
                </security>
            </binding >
        </netNamedPipeBinding>
    </bindings>

    <behaviors>
        <serviceBehaviors>
            <behavior name="MyServiceConfiguration">
                <serviceMetadata />
                <aopInstanceBehavior />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    
</system.serviceModel>

Download esempio qui

Ciauz

.net comments edit

Windows Communication Foundation è sicuramente uno tra i migliori Framework sviluppati da Microsoft negli ultimi anni: offre un’ottima estendibilità e, allo stesso tempo, risulta facile da utilizzare per chi da subito vuole realizzare servizi senza particolari esigenze.

Una cosa su cui si discute spessissimo sono le performances ottenibili con questo Framework, e, proprio come detto dalla stessa Microsoft(su questo argomento suggerisco questa sessione di Nicholas Allen della PDC 2008..), raggiungere ottime performances non è cosa facile ed immediata.
Per avere dei buoni risultati è necessario effettuare un tuning del nostro servizio, andando a modificare i numerosi parametri presenti nel file di configurazione.
Purtroppo questi parametri non sono uguali per tutti i servizi: variano infatti in base all’endpoint utilizzato, al tipo di messaggio che si restituisce, al size del messaggio, ecc, e quindi va effettuata un’analisi di questi fattori per ogni servizio.
Proprio per realizzare questo tipo di tuning, su Codeplex è presente un add-on per Visual Studio 2005-2008 (su Visual Studio 2010 sarà già incluso) che permette di effettuare un test di carico sul servizio, in modo da trovare i valori giusti per la configurazione.
Questa libreria offre le caratteristiche molto interessanti che elenco di seguito:

  • Replay of captured scenario in a unit test that can be included in a load test.
  • Support for the DataContractSerializer.
  • Support for message contracts.
  • ASMX support (beta)
  • Support for proxies generated using svcutil.
  • Support for clients that create proxies at run time from contract interfaces.
  • Supports calls to multiple services in a single scenario.
  • Supports multiple calls to the same service operation.
  • Filtering by SOAP action of which messages in the trace to replay.
  • Readable and modifiable code is generated.
  • Automatic association of trace message with proxy method (requires all operations to have a unique SOAP action).
  • Support for client and server side traces.
  • A command line tool for processing traces and generating code.
  • Visual Studio 2005/2008 integration (Team Developer, Team Test, Team Suite and for 2008 also Professional)) that can be used instead of the command line tool.

Per chi fosse interessato il download lo si trova qui.

eventi comments edit

Ok, ne ho già parlato in passato qui, ma come detto dallo sciuro Sudano in questo post, è UFFICIALE.
Alcune delle motivazioni per non mancare in questo usergroup sono già state dette qui e, se non bastano a convincervi, ci sono sempre quelle di Salvo qui.

Insomma, non potete mancare!

I miei complimenti a tutto lo staff.

Ancora un In bocca al Lupo, e speriamo di incontrarci presto tutti insieme in Sicilia.

Orange Dot Net

Ciauz

various comments edit

Sembra ufficiale, da 13 luglio per chi possiede un abbonamento MSDN, sarà possibile effettuare il download di Windows 7 RTM.

[Fonte].

Uff, ancora 7 giorni :)

asp.net comments edit

Diverse persone mi hanno chiesto il perchè, in questo post, ho deciso di utilizzare un ActionFilter al posto di un HttpModule per “pulire” il markup generato da tutti gli spazi vuoti inutili, in modo da ottimizzare banda.
Le motivazioni sono piuttosto semplici: Versatilità e Performance.

Un ActionFilter mi permette di decidere con estrema flessibilità quali Actions devono far uso di ottimizzazione e quali no; procedura che sarebbe molto più scomoda e difficile da gestire con un HttpModule.
Inoltre quest’ultimo verrebbe invocato anche quando la Action del Controller fa uso dell’OutputCache, eseguendo così delle operazioni inutilmente.
Di fatto, in una situazione come la seguente, la parte di ottimizzazzione viene invocata solo una volta per tutta la durata impostata nell’attributo OutputCache che aggiunge in memoria il markup già ottimizzato, cosa non fattibile con un HttpModule.

[OutputCache(Duration = 10000,VaryByParam = "None")]
[OptimizationFilter(Compress = true,RemoveWhiteSpace = true)]
public ActionResult Index()
{
//.....
}

Ciauz

asp.net comments edit

Spesso, quando ci si trova a realizzare pagine web il cui risultato è fortemente legato ad una variabile come potrebbe essere un ID, si può avere la necessità di effettuare un Redirect verso la pagina di customError specificata nel web.config, comunicando così al bot del motore di ricerca che il contenuto ricercato non è presente, e non deve quindi essere indicizzato.
La soluzione è presente nel .NET Framework e ci basta sollevare una HttpException specificando lo status code che si intende restituire come mostrato di seguito:

 

if (post == null)
    throw new HttpException(404, "Data not found");

Per quanto riguarda il file di configurazione, esso dovrebbe essere tipo il seguente:

<customErrors mode="On" defaultRedirect="/Errors/Generic.aspx">
    <error statusCode="403" redirect="/Errors/403.aspx" />
    <error statusCode="404" redirect="/Errors/404.aspx" />
</customErrors>

Precedentemente in questo post avevo proposto una soluzione basata su un extension method ma, esistendo già un qualcosa di analogo nel .NET Framework, aveva poco sensoe quindi il post è stato cambiato.

Ciauz