Arindam Sinha Online

August 15, 2009

User Preference using Application Settings

Background

It’s very common that we need to provide custom functionalities in our applications to the users in many respect. So that the user can do some operations at runtime. Sometimes user can resize the form, user can change the color, user can change the text etc. Obviously if our application provides all such customizations then only user can do. Now the challenge comes – when user customizes the forms of our application and wants to hold that state when he restarts the application. Per industry’s terminology this is attributed as User Preferences. In this post I would cover a very basic and easy of doing that.

Original Look and FeelUser Preference - After Saving

Suppose, the original look and feel of the form of an application is shown in the above left image. This is the form developer has created with a bluish background and some text. Now the application provides an option to customize the Form’s as well as button’s properties to be modified by the user at runtime. Now user has preferred to save the reddish form and wants to load this next time onwards. I think this problem statement can site a User preference case study. In this post I would take this one as example and would solve this with source code as well.   

Approach for implementation of User Preferences

The better option would have been to store the Form’s state in a serialized format. As Forms are not serializable it would require custom serialization through out the application with some specific properties based on the requirement.

To have some generic approach with a small piece of custom coding we can achieve the same with Application Settings.

What are Application Settings?

Application settings allow a Windows Forms or ASP.NET application to store and retrieve application-scoped and user-scoped settings. A "setting", in this context, is any piece of information that may be specific to the application or specific to the current user – anything from a database connection string to the user’s preferred default window size. Application settings works by persisting data as XML to configuration (.config) files. In most cases, the application-scoped settings are read-only; because they are program information. By contrast, user-scoped settings can be read and written safely at run time.

If you use Visual Studio, you can define settings within the Windows Forms Designer using the (ApplicationSettings) property in the Properties window. Once the applications settings are created the wrapper class with all those setting are created automatically by Visual Studio.We will discuss later in detail how applications settings are added/deleted/accessed. Now if you want to create your own custom wrapper class to have more control over the settings then this can be achived by writing class inheriting from ApplicationSettingsBase class. Custom controls can also save their own settings by implementing the IPersistComponentSettings interface, which exposes the SaveSettings method.

Implement User Preferences

So far we have come to know what’s application scope and user scope. Now we will concentrate on user scope settings with the example shown in above screenshots.

In this example I have created one form on which a button is placed to save the User Preferences. In the form I kept one Tab control with two tab pages each has PropertyGrid to change the properties of Form and Button. First tab page is to change the properties of form whereas second one is for the button.

Create Application Settings

Now we will create some application settings with user-scope.

To create new Application Settings using Visual Studio –
  • Select the form or control whose properties you want to bind to the new application setting.
  • In the Property Editor, expand the (Application Settings) item, and then click the ellipsis next to the (PropertyBindings) item underneath it.

  • In the Application Settings dialog box, click the drop-down menu for the property you want to bind and select the New command.

  • In the New Application Setting dialog box, configure the setting by giving it a name (e.g. FormForeColor) and a default value (e.g. ControlText) and setting its scope (e.g. User).

For the form I have created some application settings as shown in the red marked section in the Property Grid. Also, for the button I have created few application settings like ButtonBackColor, SaveButtonText.

To Access Application Settings

Once this is done, a wrapper class Settings is created under the Properties folder. Any of these settings can be accessed by Settings class. Now for this example the the FormForeColor can be accessed as shown below.

UserPreferenceSample.Settings defaultSettings= new Settings();
defaultSettings.FormForeColor = this.ForeColor;
Save User Preferences

Till now we have the knowledge of the creation of application settings and accessing those. So it’s only the way you want to have your User Preferences to be implemented. In this example user can change the properties of Form and Button using the PropertyGrid. Also, I provided textboxes where user can provide his/her preferred texts for Form and the Button. Once user has modified all these and clicked the save button, Application Settings have been updated with the user’s selected ones.

//UserPreferenceSample.Settings defaultSettings= new Settings(); 
//- already instantiated
//Save button's settings

 defaultSettings.ButtonBackColor = btnSave.BackColor;

 defaultSettings.SaveButtonText = btnSave.Text; 
//Save the Form's Settings
 defaultSettings.FirstFormHeader = this.Text;

 defaultSettings.FormBackColor = this.BackColor;

 defaultSettings.FormForeColor = this.ForeColor;

 defaultSettings.FormOpacity = this.Opacity;

 defaultSettings.FormWindowState = this.WindowState; 

 defaultSettings.Save();

Now onwards, whenever user starts the application he/she can see preferred view.

Sample config File

Find the sample config file entries as shown below.

<configuration>
  <configSections>
    <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
      <section name="UserPreferencesExample.Properties.Settings"   type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"   allowExeDefinition="MachineToLocalUser"   requirePermission="false" />
    </sectionGroup>
  </configSections>
  <userSettings>
    <UserPreferencesExample.Properties.Settings>
      <setting name="FirstFormHeader" serializeAs="String">
        <value>My First Form</value>
      </setting>
      <setting name="SaveButtonText" serializeAs="String">
        <value>&Save</value>
      </setting>
      <setting name="FormWindowState" serializeAs="String">
        <value>Normal</value>
      </setting>
      <setting name="FormForeColor" serializeAs="String">
        <value>ControlText</value>
      </setting>
      <setting name="FormOpacity" serializeAs="String">
        <value>1</value>
      </setting>
      <setting name="FormBackColor" serializeAs="String">
        <value>Control</value>
      </setting>
      <setting name="ButtonBackColor" serializeAs="String">
        <value>Control</value>
      </setting>
    </UserPreferencesExample.Properties.Settings>
  </userSettings>
</configuration>

Limitation of Application Settings

You cannot use application settings in an unmanaged application that hosts the .NET Framework. Settings will not work in such environments as Visual Studio add-ins, C++ for Microsoft Office, control hosting in Internet Explorer, or Microsoft Outlook add-ins and projects.

You currently cannot bind to some properties in Windows Forms. The most notable example is the ClientSize property.

Application settings has no built-in facility for encrypting information automatically. You should never store security-related information, such as database passwords, in clear text.

References

You can get the source code of the example here.

I always suggest and prefer to read MSDN. You can refer the followings articles which helped me a lot to understand this.

http://msdn.microsoft.com/en-us/library/wabtadw6.aspx

http://msdn.microsoft.com/en-us/library/fwc80dzb.aspx

http://msdn.microsoft.com/en-us/library/8eyb2ct1.aspx

August 8, 2009

Trace SOAP Request/Response XML with TraceExtension

Filed under: .NET,ASP.NET,Microsoft,SOAP,Web Service — Arindam Sinha @ 8:52 pm
Tags: , , ,

In one of my recent projects, I had to interact with one .NET Web Service (ASMX) from a Windows Desktop application. Now another java application would be accessing the same Web Service. So the java developers need a sample SOAP Request/Response XML for the Web Service. Before I start discussing on the approach of logging SOAP Request-Response XML, I would like to elaborate on same basic things Web Service referencing.

What’s WSDL File and how it’s generated?

Web Services Description Language is an XML format for describing network services as a set of endpoints operating on messages containing either document-oriented or procedure-oriented information. In a single sentence – it defines the Web Service which can be used by the clients to subscribe the web service.In case you are not aware of generating a WSDL file of a Web Service, then follow the steps mentions below –

  1. Type in your Web Service URL along with the ASMX file in the web browser.
  2. Then just append “?wsdl” at the end of URL your required WSDL will be generated in the browser. So if your URL is http://localhost/HelloWorldWebService/HelloWorldService.asmx then if you type in http://localhost/HelloWorldWebService/HelloWorldService.asmx?wsdl to generate the wsdl for your web service.

How to reference a Web Service?

This is quite easy for Visual Studio users. Using the wizard of Add Web Reference (as shown below in the images), the developer just needs to provide the URL of the Web Service. This would generate the proxy and the developer does not even need to create the WSDL separately.

Add Web Reference

Web Reference URL

 

Another approach could be generation of proxy class from WSDL file by using the WSDL.exe. Once proxy is generated, proxy class could be used for interaction with the Web Service.

SOAP and SOAP XML

Simple Object Access Protocol is a simple XML-based protocol to let applications exchange information over HTTP. SOAP is a protocol for accessing a Web Service.

A SOAP message is an ordinary XML document containing the following elements:

  • An Envelope element that identifies the XML document as a SOAP message
  • A Header element that contains header information
  • A Body element that contains call and response information
  • A Fault element containing errors and status information

Following image displays a sample SOAP Request and Response XML.

Sample SOAP Request Response XML

What’s SOAP Extension – TraceExtension?

SOAP Extensions allow developers to create very interesting applications on top of the core SOAP architecture found within .NET. It allows developers to implement encryption algorithm, compression routine, SOAP attachments etc. In this article we will focus on logging the SOAP request/response XML.

For this we need to create couple of classes –

  • Create a class that derives from System.Web.Services.Protocols.SoapExtension – TraceExtension class has been created for this
  • Create a class that derives from System.Web.Services.Protocols.SoapExtensionAttribute – TraceExtensionAttribute class has been created for this

A sample Web Service application

To understand the functionality of TraceExtension class, I will take a sample WebService and a client which subscribes that service.

  • HelloWorldWebService – This is a web service with a web method HelloWorld.
public class HelloWorldService : System.Web.Services.WebService
{

    [WebMethod]
    public string HelloWorld(string myString)
    {
        return "Hello World Service returns - " + myString;
    }
}
  • ClientSubscriber – This is a simple windows form application consuming the web reference of HelloWorldWebService. In the form, there’s a textbox and button. On click of this button, the text of the textbox will send to the web service and the result will displayed in a message box.
  • SoapMessageUtility – This utility has the actual implementation of TraceExtension. The client application has a reference to this utility to log the SOAP request/response XML.

The sample source code and binaries are available here.

Implementation of TraceExtension

We will implement the TraceExtension in the client side consuming the web service. So the Request/Response SOAP XML logs will be created in the client side.

First we will take look at the TraceExtensionAttribute class inherited from SoapExtensionAttribute. TraceExtensionAttribute must override the ExtensionType property to return the type of extension that is associated with the attribute. In this case this is nothing but TraceExtension.

public override Type ExtensionType
{
    get { return typeof(TraceExtension); }
}

For setting the priority of the ‘SoapExtension’, Priority property has been overridden also.

To have some flexibilities, few properties are created in the TraceExtensionAttribute which can be passed as parameters in the constructor.

  1. LogTypeMode – This denotes which SOAP XML to log – None, RequestOnly, ResponseOnly, RequestReponse.
  2. ReqFileName – The file name where Request SOAP XML will be logged
  3. ResFileName – The file name where Response SOAP XML will be logged

TraceExtensionAttribute class can be used at method level as shown below.

[TraceExtensionAttribute(LogType.RequestReponse,"C:\\Log\\MyReq.log","C:\\Log\\MyRes.log")]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public string HelloWorld(string myString) {
    object[] results = this.Invoke("HelloWorld", new object[] {
                myString});
    return ((string)(results[0]));
}

Now we will look into the TraceExtension class inherited from SoapExtension. The core piece of implementation is the ProcessMessage method of the SoapExtension class. This method should be overridden to have the proper implementation. Before this implementation we should be very much aware of the flow of SOAP message from the client to Web Service.

  1. When a web method in the client proxy is called, framework checks if any SOAP extensions to be invoked or not and if so, then those are called with BeforeSerialize stage.
  2. Once the serialization is done, then the extensions are called with AfterSerialize stage.
  3. The SOAP message is sent to the server and server figures out which method to route to.
  4. Then the server checks to see if any SOAP extensions (that’s us!) should be invoked, and if so, invokes them with the BeforeDeserialize event stage.
  5. The server deserializes the stream and invokes all the extensions for the AfterDeserialize stage.
  6. After the web method execution server invokes all the extensions with BeforeSerialize stage.
  7. Once the server serializes the result stream, the SOAP extensions are called with AfterSerialize stage.
  8. Result is sent back to client
  9. Now client receives the result stream and framework invokes the SOAP extensions with BeforeDeserialize event stage.
  10. Once client deserializes the result stream, SOAP extensions with AfterDeserialize stage is invoked.

In our case, we will be focused in the client side i.e. points 1,2,9 and 10. 

The key is the AfterSerialize stage (i.e. point 2) in the client, the request SOAP XML can be logged at this moment.

public void WriteOutput(SoapMessage message)
{
    FileStream fs;
    StreamWriter w = null; 
    
    try
    {
        if (_logTypeMode.Equals(LogType.RequestOnly) || _logTypeMode.Equals(LogType.RequestReponse))
        {
            _newStream.Position = 0;
            fs = new FileStream(_reqFilename, FileMode.Append,
                FileAccess.Write);
            w = new StreamWriter(fs);

            string soapString = "SoapRequest";
            w.WriteLine("-----" + soapString + " at " + DateTime.Now);
            w.Flush();
            Copy(_newStream, fs);
            w.Close();

        }
    }
    catch (Exception ex)
    {
    }
    finally
    {
        if (w != null)
            w.Close();
        _newStream.Position = 0;
        Copy(_newStream, _oldStream);
    }
}

The same is applicable for the BeforeDeserialize stage (i.e. point 9) to log the response SOAP XML. The WriteInput method logs the response XML.

Safety and Configurability

The whole purpose of this article is to log the request-response SOAP XML. In case of any exception while logging would cause interruption in the web service invocation. So the WriteInput and WriteOutput methods in TraceExtension class should take care of proper exception handling. In my case I kept a blank catch block which can be modified with some exception logging mechanism but that should not impact the normal web service invocation.

Already I tried to provide some flexibilities in the TraceExtensionAttribute with few properties. These can be set while instantiating the attribute in the method level. Also, TraceExtension class can support the following entries in (config files web.config/app.config).

<appSettings>
  <add key ="REQ_LOGFILE" value="c:\log\SOAPReq_log.txt"/>
  <add key ="RES_LOGFILE" value="c:\log\SOAPRes_log.txt"/>

  <add key ="LogTypeMode" value="3"/>
<!-- None = 0,
      RequestOnly = 1,
      ResponseOnly = 2,
      RequestReponse = 3 -->
</appSettings>

If both config entries and attribute parameters are provided, then config entries would override that. So my utility (i.e. SoapMessageUtility.dll) can be directly used with the above configuration entries.

References

You can download the code and binaries by clicking here. I would suggest you all to have a look into the MSDN link on this. Also for beginners to SOAP, the tutorial from w3schools might be helpful.

Next Page »

Create a free website or blog at WordPress.com.