Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

May 2009 - Posts

Off Proc Session State and Custom Classes

If you want to store a custom class in an off-proc session (SQL Server, ASP.NET State Service, custom) that serializes objects, you must be aware that if the base class for your custom class implements, directly or indirectly, System.Runtime.Serialization.ISerializable, you must add a public or protected constructor to your class that has the following signature:

public MyClass(SerializationInfo info, StreamingContext context): base(info, context)

{

}

As you can see, you just have to call the base class' constructor that receives the same parameters. This is because in .NET an interface cannot specify constructors, but, in the case of ISerializable, the constructor is also a requirement, not just method GetObjectData.

Posted: May 26 2009, 09:53 AM by Ricardo Peres | with 5 comment(s)
Filed under: ,
Enterprise Library Contrib 3.1 Released

Version 3.1, fully compatible with Enterprise Library 4.1 and .NET 3.5, was released. You can get it from http://www.codeplex.com/entlibcontrib.

What does it contain, you may ask? Well, here is the list from their site:

What's in EntLib Contrib?

The latest release of EntLib Contrib is Enterprise Library Contrib v3.1 May 2009. It contains the following functionality. For more detailed documentation, follow the link to the release home page.

  • Common Block extensions
    • TypeConfigurationElement<T>, AnonymousConfigurationElement
  • Data Access Application Block extensions
    • MySql, SQLite and SqlEx providers
  • Exception Handling Application Block extensions
    • SqlException Wrap Handler
  • Logging Application Block extensions
    • LogParser, TimeStampParser
  • Policy Injection Application Block extensions
    • PostSharp4EntLib
    • New matching rules: And, Or and Not
    • New call handlers: CursorCallHandler, OneWayCallHandler, SynchronizedCallHandler, ThreadSafeCallHandler, TransactionScopeCallHandler
  • Resource Application Block 3.1
    • Configurable providers for Globalization and Localization
    • Full application block complete with support for the console, instrumentation and group policies
  • Validation Application Block extensions
    • New validators: CollectionCountValidator, CompositeRulesetValidator, TypeValidator<T>, ObjectValidator<T>, EnumDefinedValidator
    • Designtime enhancements: Lightweight type picker, Test command
    • Other extensions: Default validators, Argument Validation, ExternallyConfigurableObjectValidator
Circular References in WCF

Updated: thanks to Nobody for the remark! 

Suppose you want to transmit a list of items where possibly some of them refer to other items on the list. For example:

[DataContract]

public class MenuItem

{

    [DataMember]

    public String Text { get; set; }

    [DataMember]

    public String NavigationUrl { get; set; }

    [DataMember]

    public MenuItem Parent { get; set; }

}

If you want to preserve bandwidth, and avoid circular references - for example, one menu item having itself as its parent - you should use the IsReference property on the [DataContract] attribute:

[DataContract(IsReference = true)]

This property exists since .NET 3.5 SP1 (and .NET 3.0 SP1, for that matter), and it makes it unnecessary to write a specific behavior to set the preserveObjectReferences on the DataContractSerializer class (see Sowmy's post: http://blogs.msdn.com/sowmy/archive/2006/03/26/561188.aspx). A welcome addition!

ASP.NET Bundle

Unit Testing ASP.NET? ASP.NET unit testing has never been this easy.

Typemock is launching a new product for ASP.NET developers – the ASP.NET Bundle - and for the launch will be giving out FREE licenses to bloggers and their readers.

The ASP.NET Bundle is the ultimate ASP.NET unit testing solution, and offers both
Typemock Isolator, a unit test tool and Ivonna, the Isolator add-on for ASP.NET unit testing, for a bargain price.

Typemock Isolator is a leading .NET unit testing tool (C# and VB.NET) for many ‘hard to test’ technologies such as SharePoint, ASP.NET, MVC, WCF, WPF, Silverlight and more. Note that for unit testing Silverlight there is an open source Isolator add-on called SilverUnit.

The first 60 bloggers who will blog this text in their blog and tell us about it, will get a Free Isolator ASP.NET Bundle license (Typemock Isolator + Ivonna). If you post this in an ASP.NET dedicated blog, you'll get a license automatically (even if more than 60 submit) during the first week of this announcement.

Also 8 bloggers will get an additional 2 licenses (each) to give away to their readers / friends.

Go ahead, click the following link for more information on how to get your free license.

NHibernate Property Validator for ASP.NET

Suppose you want to validate an ASP.NET control based on some validation attributes from a property. You may know that the Enterprise Library Application Block's PropertyProxyValidator does just this, the problem is that it uses Enterprise Library's own validation attributes. If you want to use NHibernate Validator's, your on your own.

I have written a small validator control, based on Enterprise Library's, that may come in handy. Here is the code:

public class NHibernatePropertyValidator: BaseValidator

{

    private ValidationSummaryDisplayMode displayMode;

    private String propertyName;

    private String sourceTypeName;

    protected override void OnInit(EventArgs e)

    {

        if ((this.Enabled == true) && (this.Visible == true))

        {

            this.Page.RegisterRequiresControlState(this);

        }

        base.OnInit(e);

    }

    protected override void LoadControlState(Object savedState)

    {

        Object [] state = savedState as Object [];

        base.LoadControlState(state[0]);

        this.displayMode = (ValidationSummaryDisplayMode) state [ 1 ];

        this.PropertyName = (String) state [ 2 ];

        this.SourceTypeName = (String) state [ 3 ];

    }

    protected override Object SaveControlState()

    {

        Object [] state = new Object [ 4 ];

        state [ 0 ] = base.SaveControlState();

        state [ 1 ] = this.DisplayMode;

        state [ 2 ] = this.PropertyName;

        state [ 3 ] = this.SourceTypeName;        return (state);

    }

    protected override Boolean EvaluateIsValid()

    {

        Type type = Type.GetType(this.SourceTypeName, false);

        if (type != null)

        {

            PropertyInfo prop = type.GetProperty(this.PropertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);

 

            if (prop != null)

            {

                IClassValidator validator = new ClassValidator(type);

                Object obj = Activator.CreateInstance(type);

                Object value = this.GetControlValidationValue(this.ControlToValidate);

                prop.SetValue(obj, Convert.ChangeType(value, prop.PropertyType), null);

                InvalidValue [] results = validator.GetInvalidValues(obj, this.PropertyName);

                base.ErrorMessage = this.formatErrorMessage(results);

                return (results.Length == 0);

            }

        }

        base.ErrorMessage = String.Empty;

 

        return (true);

    }

    private String formatErrorMessage(InvalidValue [] results)

    {

        String str = String.Empty;

        String str2 = String.Empty;

        String str3 = String.Empty;

        String str4 = String.Empty;

        StringBuilder builder = new StringBuilder();        switch (this.DisplayMode)

        {

            case ValidationSummaryDisplayMode.List:

            str3 = "<br/>";

            break;

            case ValidationSummaryDisplayMode.SingleParagraph:

            str3 = " ";

            str4 = "<br/>";

            break;

            default:

            str = "<ul>";

            str2 = "<li>";

            str3 = "</li>";

            str4 = "</ul>";            break;

        }

        if (results.Length != 0)

        {

            builder.Append(str);

 

            foreach (InvalidValue result in results)

            {

                builder.Append(str2);

                builder.Append(result.Message);

                builder.Append(str3);

            }

            builder.Append(str4);

        }

 

        return (builder.ToString());

    }

    [Browsable(true)]

    [DefaultValue(ValidationSummaryDisplayMode.List)]

    public ValidationSummaryDisplayMode DisplayMode

    {

        get

        {

            return (this.displayMode);

        }

        set

        {

            this.displayMode = value;

        }

    }

    [Browsable(
true)]

    [DefaultValue("")]

    public String PropertyName

    {

        get

        {

            return (this.propertyName);

        }

        set

        {

            this.propertyName = value ?? String.Empty;

        }

    }

    [
Browsable(true)]

    [DefaultValue("")]

    public String SourceTypeName

    {

        get

        {

            return (this.sourceTypeName);

        }

        set

        {

            this.sourceTypeName = value ?? String.Empty;

        }

    }

}

Basically, it uses the NHibernate Validator's ClassValidator to do the actual validation.

This is how you would use it:

<asp:TextBox runat="server" ID="email"/>

<xxx:NHibernatePropertyValidator runat="server" ControlToValidate="email" SourceTypeName="SomeClass, SomeAssembly" PropertyName="Email"/>

If you combine it with Web Client Software Factory's ServerSideValidationExtnder, you can even have client-side (AJAX) validation. Give it a try!

ODP.NET Associative Arrays

Through ODP.NET you can use Oracle's Associative Array feature. Unfortunately, there is a limitation: you cannot have associative arrays with an index type other that number.

If you have this stored procedure:

PACKAGE
MyPackage AS

TYPE AssocArrayVarchar2_t IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER;

PROCEDURE MyStoredProcedure

(

    Param1 IN AssocArrayVarchar2_t

);

END MyPackage;

You can use this code to call it:

using (OracleConnection con = new OracleConnection(@"DATA SOURCE=(DESCRIPTION=(ADDRESS=(COMMUNITY=MyCommunity)(PROTOCOL=TCP)(HOST=MyHost)(PORT=MyPort))(CONNECT_DATA=(SID=MySid)));USER ID=MyUsername;PASSWORD=MyPassword;Promotable Transaction=local"))using (OracleCommand cmd = con.CreateCommand())

{

    con.Open();

    cmd.CommandText = @"MyPackage.MyStoredProcedure";

    cmd.CommandType = CommandType.StoredProcedure;   

    OracleParameter param1 = cmd.Parameters.Add("param1", OracleDbType.Varchar2, ParameterDirection.Input);

    param1.CollectionType = OracleCollectionType.PLSQLAssociativeArray;

    param1.Value = new String[] { "First Element", "Second Element", "Third Element" };

    cmd.ExecuteNonQuery();

}

Using MTOM with WCF

Suppose you want to transmit large binary contents (a file, for example) through WCF. In the usual way, you would use a classe decorated with a [DataContract] attribute, and you would have inside of it a property of type Byte[], marked with a [DataMember], where the actual contents would be placed. There is a problem with this solution, however: being SOAP based exclusively in text (it is just XML), if you want to send special characters inside of it, you must convert them into text, using common encoding techniques such as Basw 64. Now, WCF does this for you, you just have to supply the byte array, and it does all the work, the problem is that Base 64 typically increases the total size by 33%.

The good news is that the good guys at W3C have developed a standard, named MTOM - Message Transmission Optimization Mechanism - that allows you to send binary content over the wire as is, that is, without translation to text. You can read about it here. I will not go into details, in order to use MTOM, you must do the folowing:

  1. The method that is sending MTOM content can only receive or return classes that have the [MessageContract] attribute, not [DataContract], or "primitive" types;
  2. All the byte array properties must have a [MessageBodyMember] attribute, not [DataMember] nor [MessageHeader], and all the other properties must have a [MessageHeader] attribute;
  3. Instead of Byte[] you can also pass a Stream object, the results are the same;
  4. All eventual classes that the parameter or return classes derive from must also have the [MessageContract] attribute;
  5. In the <binding> elements for you service (both client and server), you must set the messageEncoding attribute to Mtom.

And that's it! You will notice a significant throughput increase, specially for large contents.

See this example:

[MessageContract]

public class FileResponse

{

    [
MessageHeader]

    public String Filename { get; set; }

    [MessageBodyMember]    public Byte[] Contents { get; set; }

}

[ServiceContract]

public interface IFileService

{

    [
OperationContract]    FileResponse GetFile(String filename);

}

/* client and server */

<
bindings>

    <wsHttpBinding>

        <
binding name="WsHttpMtomBinding" messageEncoding="Mtom" />

    </wsHttpBinding>

 </bindings>

/* server only */ 

<services> 

    <
service behaviorConfiguration="Behavior" name="FileService">

        <endpoint binding="wsHttpBinding" bindingConfiguration="WsHttpMtomBinding" contract="IFileService">

     </service>

</services>

/* client only */ 

<client>

    <endpoint address="http://localhost:8001/FileService.svc" binding="wsHttpBinding" bindingConfiguration="WsHttpMtomBinding" contract="IFileService" name="IFileService"/>

</client>

New Version of AJAX Control Toolkit Released

Release 30512. Get it from http://www.codeplex.com/AjaxControlToolkit.

Three new controls added: HTMLEditor, ColorPicker and ComboBox. See the samples live at http://www.asp.net/ajax/AjaxControlToolkit/Samples/.

SQL Server 2008 Developer Training Kit Released

Get it here: http://www.microsoft.com/downloads/details.aspx?FamilyID=E9C68E1B-1E0E-4299-B498-6AB3CA72A6D7&displaylang=en.

More Posts