Showing posts with label AppDomain. Show all posts
Showing posts with label AppDomain. Show all posts

Wednesday, April 13, 2011

Hosting SQL CE based Entity Models in WCF Data Service

While developing an application in ASP.net for my friend I realized that we can not SQL Compact Edition with ASP.net. When you try to do that you would get this error page.

SQL Compact Edition error when used with ASP.net
The server encountered an error processing the request. The exception message is 'SQL Server Compact is not intended for ASP.NET development.'. See server logs for more details. The exception stack trace is: 

at System.Data.SqlServerCe.SqlCeRestriction.CheckExplicitWebHosting() at System.Data.SqlServerCe.SqlCeConnection..ctor() at System.Data.SqlServerCe.SqlCeProviderFactory.CreateConnection() at System.Data.EntityClient.EntityConnection.GetStoreConnection(DbProviderFactory factory) at System.Data.EntityClient.EntityConnection.ChangeConnectionString(String newConnectionString) at System.Data.EntityClient.EntityConnection..ctor(String connectionString) at System.Data.Objects.ObjectContext.CreateEntityConnection(String connectionString) at System.Data.Objects.ObjectContext..ctor
I got this when I was hosting WCF DataService in the ASP.net application exposing my Entity Model. The entities were based on a SQL CE database. To see this message, we need to set the behavior of service to allow the exception details to be shown to the user by this setting on the WCF Data Service.
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class MyDataService : DataService<App.ModelEntities>
{
    ...
}
Otherwise we see the following message when we run the application:

Although this is more secure message as we are not showing the stack trace to the user but during development this message seems very irritating. In order to avoid this and to get the detailed message set the above specified Service Behavior for the WCF Data Service.

This must be remembered that this limitation seems more like a suggestion by Microsoft so as to discourage the use of SQL Server Compact Edition for public facing systems because of its security limitations. But there might be valid reasons to still use SQL CE for ASP.net applications for demo applications or in-house developed applications. In order to get around that we can use AppDomain slots to set SQLServerCompactEditionUnderWebHosting to true. This results in allowing the use of SQL Server Compact edition by the runtime. We can set that during application startup in Global.asax.
public class Global : System.Web.HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        // Code that runs on application startup
        AppDomain.CurrentDomain.SetData("SQLServerCompactEditionUnderWebHosting", true);
    }
}
Now when we run the application we can see the service successfully giving XML data. We have discussed about AppDomain slots here:

http://shujaatsiddiqi.blogspot.com/2011/01/in-this-post-we-will-discuss-named-slot.html

Sunday, January 23, 2011

C# Static Members' Not-So-Famous features

In this post we will be discussing some known but not-so-famous features of static members in C#. It is possible that you might be already aware of these special features.

Static Members and Application Domains:
Application domains are provided in a .net process to provide intra-process isolation. This isolation also includes the isolation of static members. Static members are static (shared) within the context of an application domain. It includes static fields, classes and constructors. As we know that:

Static Constructor is executed only once for a type

Now lets update this knowledge:

Static constructor is executed only once for a type PER APPLICATION DOMAIN

Let's consider Student class. This class only has a single static member MessageOfTheDay.

class Student
{
public static string MessageOfTheDay = "Default Message";
}

We create a Window as follows:

<Window x:Class="WpfApplication_Generic_Static.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid>
<Label Content="Message Of The Day" Height="27" HorizontalAlignment="Left" Margin="8,0,0,0"
Name="labelMessage" VerticalAlignment="Top" Width="200" FontWeight="Bold" />
<TextBox Height="231" HorizontalAlignment="Left" Margin="8,23,0,0"
Name="textBoxMessage" VerticalAlignment="Top" Width="481" />
<Button Content="Demonstrate static variables across AppDomains" Height="34" HorizontalAlignment="Left" Margin="6,265,0,0"
Name="btnSetMessage" VerticalAlignment="Top" Width="292" Click="btnSetMessage_Click" />
</Grid>
</Grid>
</Window>

The code behind of the Window is as follows:

public partial class MainWindow : Window
{
AppDomain appDomain;
public MainWindow()
{
InitializeComponent();
appDomain = AppDomain.CreateDomain("MyNewDomain");
}

private void btnSetMessage_Click(object sender, RoutedEventArgs e)
{
Student.MessageOfTheDay = this.textBoxMessage.Text;
appDomain.DoCallBack(displayMessage);
displayMessage();

}

private static void displayMessage()
{
string message = string.Format("AppDomain Name: {0}\n\nMessage of the Day: {1}",
AppDomain.CurrentDomain.FriendlyName, Student.MessageOfTheDay);

MessageBox.Show(message);
}
}

As you can see this Window has a single text box and a button. Clicking the button handles the Click event of the button using btnSetMessage_Click handler. The handler assigns a new value to MessageOfTheDay static member of Student class. This also executes displayMessage callback in a different application domain appDomain and shows the value of Student.MessageOfTheDay in this application domain. In order to prove that the current domain still holds the text entered in the textbox, we are showing the value [in the Base AppDomain] of Student.MessageOfTheDay. Let's run this and enter some text in the TextBox. Let's Enter "Muhammad Siddiqi".



So after clicking the button there would be two message boxes displayed. Can you guess the messages in those message boxes?

Based on the above discussion, the following message boxes are displayed:





This proves our point. Although we have set Student.MessageOfTheDay in the current domain but the change is not visible in the other domain as they are isolated.

Static Member initialization and Static constructors:
If we are setting the value of a static field in initializer and static member. What value would it hold? The answer is whatever would be executing last would be resulting in the value of static field. In a previous post, we have discussed about this:



In words: Initializers are executed from child class to base class. The same is true for the value assignment to the constructors in the inheritance hierarchy. The constructors, themselves, are executed from Base class to child class. Additionally, the constructors are always executed when both initializers are value assignment is finished. So in the case of static members also, the static initializer is always executed before static constructor. Based on this discussion, you would always find the value of a static field as set in the static constructors when you would use it first time if they are set in both static initializer and static constructor.

Let's have a class named Banner as follows:

static class Banner
{
public static string MessageOfTheDay = "Default Banner Message";

static Banner()
{
MessageOfTheDay = "Default Banner Message from static constructor";
}
}

Since Banner has only static members, we can declare itself as static. Now if we execute the following code, you can guess what should be displayed:

private void btnBannerMessage_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(Banner.MessageOfTheDay);
}

This results in the following MessageBox:



This is exactly as we discussed above.

Generics and their Static Members:
As we know that for a Generic type, The whole new set of classes are generated for generic classes for each specialized usage by JIT compiler at runtime. That is why static members in a Generic are not shared across different type of TypeMembers. They are only shared within similar TypeMembers. Here TypeMember:
class Classlt;TypeMember>
{
TypeMember StaticField;
}

Let us declare a generic class MyItem as follows:

class MyItem <T>
{
public static T Item { get; set; }
}

Now we use this class as follows:

private void btnGenericItem_Click(object sender, RoutedEventArgs e)
{
//int type for Generic Type
MyItem<int>.Item = 1;

//decimal type for Generic Type
MyItem<decimal>.Item = 2.3m;

//Showing message box for verification
MessageBox.Show(
string.Format("MyItem<int>.Item : {0}, MyItem<decimal>.Item : {1}",
MyItem<int>.Item.ToString(), MyItem<decimal>.Item.ToString()));
}

Can you guess what would be the contents of the MessageBox?

Now verify if it matches from actual Message box.



As you can see that both specific type generated for Generic holds different values of static members, so they are not shared.

Summary:
As a summary of this discussion:

1. Static members are not shared across application domain.
2. Static constructors are always executed after static initializers.
3. Static members are not shared across different specific type generated for Generics.

Download:

WPF - Inter-Domain Messaging using AppDomain Slots

In this post we will discuss Named slot. Slots are used for inter-domain messaging. A sender from one application domain sets the message in other application domain. Any receiver in the other domain can receive the message from the slots.



Let's define a Window to demonstrate the usage of AppDomain's slot to send and receive message to the Application Domain.

<Window x:Class="AppDomain_Slots.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window" Height="350" Width="525">
<Grid>
<Label Content="Message" Height="27" HorizontalAlignment="Left" Margin="8,0,0,0"
Name="labelMessage" VerticalAlignment="Top" Width="96" FontWeight="Bold" />
<Button Content="Send Message" Height="34" HorizontalAlignment="Left" Margin="12,265,0,0"
Name="btnSendMessage" VerticalAlignment="Top" Width="150" Click="btnSendMessage_Click" />
<Button Content="Receive Message" Height="33" HorizontalAlignment="Left" Margin="337,265,0,0"
Name="btnReceiveMessage" VerticalAlignment="Top" Width="154" Click="btnReceiveMessage_Click" />
<TextBox Height="231" HorizontalAlignment="Left" Margin="8,23,0,0"
Name="textBoxMessage" VerticalAlignment="Top" Width="481" />
</Grid>
</Window>

Instantiating Application Domain:
Let's create a new application domain appDomain. We assign it a friendly name MyNewDomain.
AppDomain appDomain;

public MainWindow()
{
InitializeComponent();
appDomain = AppDomain.CreateDomain("MyNewDomain");
}

Sending message to Application Domain:
Let's write some message in a named slot of the application domain. The name of the slot is MyMessage. We will be using the text entered in the Message text box.
private void btnSendMessage_Click(object sender, RoutedEventArgs e)
{
string message = this.textBoxMessage.Text;
appDomain.SetData("MyMessage", message);
}

Receiving message in Application Domain:
Now let's receive this message in the other application domain. We would be getting this message in a callback executed in the other application domain using DoCallBack method. Since displayMessage is a static method, we don't need to serialize it.
private void btnReceiveMessage_Click(object sender, RoutedEventArgs e)
{
appDomain.DoCallBack(displayMessage);
}

static void displayMessage()
{
string message = (string)AppDomain.CurrentDomain.GetData("MyMessage");

MessageBox.Show(string.Format("Domain: {0}, Message: {1}",
AppDomain.CurrentDomain.FriendlyName,
message));
}

Let's enter some text in the Text box and hit Send Message button. This would write message to the slot MyMessage in MyNewDomain application domain.



Now click Receive Message button. This would get data as in the slot and show it in the message box as follows:



Download: