Developing Distributed Enterprise Applications using .NET

ISDV 211

Lec2: Remoting: Basics

Design patterns:

The design pattern is architecture for constructing flexible and maintainable object oriented software.

Design patterns help constructing reliable software and promote code reusability. It helps to improve and shorten the design phase in the software development life cycle.

A group called the “gang of four” introduced design Pattern in the period 1991-1994. They described 23 design patterns, grouped into three main categories: creational, structural, and behavioral.

Creational design patterns describe techniques for instantiating objects, and the related issues such as prevent creating more than one object, or determine the type of the created object at run time.

Structural design patterns describe common ways to organize classes and objects and their related issues such as determining each class responsibility and preventing overlapping between classes’ responsibilities.

Behavioral design patterns assign responsibilities to objects, and model objects collaboration.

Following is a list of the 23 main design patterns that was introduced by the gang of four.

Creational / Structural / Behavioral
Abstract Factory / Adapter / Chain-of-Responsibility
Builder / Bridge / Command
Factory Method / Composite / Iterator
Prototype / Decorator / Interpreter
Singleton / Façade / Observer
Flyweight / Mediator
Proxy / Memento
State
Strategy
Template Method
Visitor

More design patterns have been introduced over the time including concurrency patterns, and architectural patterns.

Concurrency patterns provide strategies for designing systems with concurrent activities (multithreaded).

Architectural patterns provide strategies for designing sub-systems and manage the interaction between them.

The Factory Method Pattern:

Provides a class that returns an object representing one of several subclasses derived from an abstract base class depending on the argument provided. Factory Method lets a class defer instantiation to subclasses.

Following is an example of the factory method design pattern. The purpose of this example is to create a method that returns one of two possible objects: Employee or Student. The example uses reflection ( provided by System.Activator class) to load the class at runtime and create the object of the required type. The following classes are created as part of a Class Library project type:

//Product

using System;

using System.Collections.Generic;

using System.Text;

namespace FactoryDesignPattern

{

publicabstractclassPerson

{

protectedstring id;

protectedstring name;

abstractpublicstring GetInfo();

publicstring Id

{

set { id = value; }

}

publicstring Name

{

set { name = value; }

}

}

}

//ConcreteProduct

using System;

using System.Collections.Generic;

using System.Text;

namespace FactoryDesignPattern

{

publicclassEmployee : Person

{

publicoverridestring GetInfo()

{

return"Employee Info: \n emp ID:" + id + "\n emp name:" + name;

}

}

}

//ConcreteProduct

using System;

using System.Collections.Generic;

using System.Text;

namespace FactoryDesignPattern

{

publicclassStudent: Person

{

publicoverridestring GetInfo()

{

return"Studnet Info: \n st ID:" + id + "\n st name:" + name;

}

}

}

//Creator

using System;

using System.Collections.Generic;

using System.Text;

namespace FactoryDesignPattern

{

publicabstractclassCreator

{

publicabstractPerson Create();

}

}

//ConcreteCreator

using System;

using System.Collections.Generic;

using System.Text;

using System.Configuration;

namespace FactoryDesignPattern

{

publicclassFactory : Creator

{

publicoverridePerson Create()

{

// Load the class file name from a the configuration file (app.config)

string myClassName = ConfigurationManager.AppSettings["classNameEmp"];

Type t = Type.GetType(myClassName);

Person p = (Person)Activator.CreateInstance(t);

return p;

}

}

}

To test this design pattern, we create a Console Application:

using System;

using System.Collections.Generic;

using System.Text;

using FactoryDesignPattern;

namespace FactoryDesignPatternTest

{

classProgram

{

staticvoidMain(string[] args)

{

Factory f = newFactory();

Person p = f.Create();

p.Id = "1";

p.Name = "john";

Console.WriteLine(p.GetInfo());

Console.ReadLine();

}

}

}

Notice that you need to add a reference to the FactoryDesignPattern DLL.

The configuration is provided as part of the Console application by including Application configuration file:

<?xmlversion="1.0"encoding="utf-8"?>

configuration

appSettings

addkey="classNameEmp"value="FactoryMethod.Employee" </add

addkey="className"value="FactoryMethod.Student" </add

</appSettings

</configuration

.NET Component:

Components are classes that are intended to be used by other applications and are compiled into binary format known as assembly (dll or exe)

Components are deployed in assemblies that can be versioned and secured.

Since a component may be used by more than one application, it has to be well written, tested and in certain cases, provides code access security mechanism.

In distributed applications, components can be developed to serve two purposes:

  • Service provider: stateless components that provide functionality for certain business logic. Service provider components can provide services to client applications or other components. A service provider component can be also exposed as web service to provide service to third party applications/ components. Components that are developed as part of distributed application architecture are executed out of process which means that the component can be hosted on the same computer or on another computer.
  • Information container: stateful components that provide information packages but do not provide functionality. This kind of components are never intended to be executed out of process and usually used by service provider components or other applications.

An information container class can extend the System.ComponentModel.MarshalByValueComponent class to prevent the component from being manipulated remotely. This does not prevent us from sending an object of this class from one computer to another. To do this we need to serialize this kind of classes by adding the [Serializable] attribute to the class definition.

As an example of components, assume that we need to access certain database and manipulate records in a table called customer. To create the component, we need to create two classes: one that encapsulates the customer information (as an object) and the other is the service provider that encapsulates the actual database access code.

using System;

namespace ComponentEx

{

///<summary>

/// Summary description for Class1.

///</summary>

class Class1

{

///<summary>

/// The main entry point for the application.

///</summary>

[STAThread]

staticvoidMain(string[] args)

{

Customer c= new Customer();

c.Cust_id=1;

c.Cust_name="John";

c.Cust_address="test address";

DBManager mng= new DBManager();

mng.AddCustomer(c);

}

}

// information container- stateful

class Customer

{

privateint cust_id;

privatestring cust_name;

privatestring cust_address;

publicint Cust_id

{

get{return cust_id;}

set{cust_id=value;}

}

publicstring Cust_name

{

get{return cust_name;}

set{cust_name=value;}

}

publicstring Cust_address

{

get{return cust_address;}

set{cust_address=value;}

}

}

// service provider

class DBManager

{

publicvoid AddCustomer(Customer cust)

{

// database code

}

publicvoid UpdateCustomer(Customer cust)

{

// database code

}

publicvoid DeleteCustomer(Customer cust)

{

// database code

}

public Customer FindCustomer( int custId)

{

Customer cust=null;

// database code

return cust;

}

}

}

If a component needs design-time support or need to provide a mechanism for deterministically release resources, it should either implement the System.ComponentModel.IComponent interface or extend a class that implements this interface(such as System.ComponentModel. Component).

When a component provides design-time support, it can be added to the VS.NET toolbar. It can be added and configured like any standard control in VS.NET.

Review of Assemblies:
Assemblies are collections of types and resources that create a logical unit of functionality. Assemblies are usually deployed as DLL or EXE files and they constitute the basic unit of versioning, reusability, security and deployment in .NET.

A class library assembly is a set of types that can be used in other assemblies. They are none executables, therefore they must be referenced by an executable application.

An assembly can consist of 4 parts:

  • The assembly manifest or metadata: contains information exposed to the CLR about the assembly. A manifest contains the following information:
  • Identity: the name and version number of the assembly. It can also contain optional information such as signature information.
  • Types and Resources: contains a list of all types that will be exposed to the CLR. It also includes information about how these types can be accessed.
  • Files: Contains a list of all the files in the assembly with their dependency information.
  • Security permissions: Contains security permissions required by the assembly.

The VS.NET compiles and exposes the manifest files to the CLR. The developer is responsible for setting the metadata.

  • The type metadata: Contains information about the types contained in the assembly. The metadata describes the assembly identity( in a file called AssemblyInfo.cs that is included in the project). The file includes many assembly identity attributes that are set to null be default.
  • The intermediate code for the assembly.
  • The resource files: non executable data contained in the assembly such as string data, image data that are pertain to particular culture.

The assembly version has 4 parts in the format: Major version. Minor version. Build. Revision

If the version is not set in the assembly manifest file, the compiler will assign the value 0.0.0.0 to the assembly’s version. We can use the wild card * in the version number to instruct the compiler to automatically generate that part. For example:

[assembly: AssemblyVersion(“1.0.1.*”)]

We can have two kinds of assemblies: private and shared. Private assembly is an assembly that is used by one application and usually stored in the same location as the application’s executable file(s). Shared Assemblies can be used by multiple applications.

When you add a reference to a private assembly, VS.NET creates a copy of this file in the project executable folder. Each project will have its own copy of the private assembly. To instruct the .NET to look for an assembly in another location, we need to create an application configuration file and use the codeBase element as shown in the following example:

<?xmlversion="1.0"encoding="utf-8"?>

configuration

runtime

assemblyBindingxmlns="urn:schemas-microsoft-com:asm.v1">

dependentAssembly

assemblyIdentityname="BDManager"/>

codeBasehref="compFolder\DBManager.dll"/>

</dependentAssembly

</assemblyBinding

</runtime

</configuration

The href can point to a URL, for example href=" As an alternative,we can also use the probing element:

<?xmlversion="1.0"encoding="utf-8"?>

configuration

runtime

assemblyBindingxmlns="urn:schemas-microsoft-com:asm.v1">

probingprivatePath="compFolder;myFolder "/>

</assemblyBinding

</runtime

</configuration

Both elements can only point to directories within the application’s directory, they cannot point to directories up in the file system.

Only one copy of a shared assembly can exist on any computer, but multiple applications can reference this assembly. We can also have multiple versions of an assembly present on one computer.

To make an assembly shared, it must be signed with a strong name and installed in the Global Assembly Cash (GAC) using the gacutil.exe utility.

A strong name is a unique name that identify the assembly and consists of information about the assembly such as name, version, culture settings, security information represented by the private/ public key pairs. The private key is used to compile the assembly and the public key is embedded in the assembly. When an application uses the assembly, the CLR uses the public key to decode information from the assembly manifest. Anything encrypted with private key, can be read only with the corresponding public key and vise versa. Therefore no one can manipulate your assembly without having access to your private key.

To sign an assembly we can use the sn.exe tool:

sn –k assemblyKey.snk

Once you have the key file, set the AssemblyKeyFile and AssemblyVersion as shown in the following example:

[assembly: AssemblyVersion(“1.0.1.1”)]

[assembly: AssemblyKeyFile(“assemblyKey.snk”)]

As an alternative approach, we can also install the key into a list of digital signatures that is stored by the Windows cryptography service provider and set the AssemblyKeyName attribute. To install the strong name key to the CSP, we use the flowing command:

sn –i assemblyKey.snk MyKey

After that we need to modify the above attributes as follows:

[assembly: AssemblyVersion(“1.0.1.1”)]

[assembly: AssemblyKeyFile(“”)]

[assembly: AssemblyKeyName(“MyKey”)]

Once you have added these attributes, build the assembly project and deploy the assembly to the GAC:

Gacutil.exe /i MyAssembly.dll

When we install an assembly, we provide the assembly’s file name. To uninstall an assembly from the cash, we use the /u flag and provide the assembly’s name and any other options. For example:

Gacutil.exe /u AssemblyName Version=1.1.1.1 Culture=en

We can also view the content of an assembly using the ILDasm.exe utility.

You can also create a strong name assembly, but delay assembly signing during development. First you have to create the public/private key file using sn tool as shown above. Second, you have to create the public key file using the following command:

sn –p assemblyKey.snk assemblyPublicKey.snk

Also we need to add the AssembyDelaySign and AssemblyKeyFile as shown in the following example:

[assembly: DelaySign(true)]

[assembly: AssemblyKeyFile(“assemblyPublicKey.snk”)]

This instruct toe compiler to add the public key to the assembly, but not to sign the assembly with the private key.

The third step is to instruct the compiler to disable signature verification.

sn –Vr myComp.dll

Without this step the assembly loading will fail. To enable signature verification, use the following command

sn –Vu myComp.dll

When the component development is completed and it’s ready to be released, it has to be signed properly using the private key. This is done using the following command:

sn –R myCopm.dll assemblyKey.snk

To override the default binding of an assembly after it has been deployed, you need to use configuration file to redirect the binding as shown in the following example:

<?xmlversion="1.0"encoding="utf-8"?>

configuration

runtime

assemblyBindingxmlns="urn:schemas-microsoft-com:asm.v1">

dependentAssembly

assemblyIdentityname="BDManager"publicKeyToken="b03f5f7f11d50a3a"/>

bindRedirectoldVersion="1.0.0.0-1.9.9.9"newVersion="2.0.0.0"/>

</dependentAssembly

</assemblyBinding

</runtime

</configuration

To explicitly load an assembly programmatically, we can use one of the static methods System.Reflection.Assembly.LoadFrom and System.Reflection.Assembly.Load.

We should use the Load method if we know the name or identity of an assembly. For example:

System.Reflection.Assembly myA= System.Reflection.Assembly.Load(“System.Drawing, Version=1.0.5000.0, Culture=netural, PublicKeyToken=b03f5f7f11d50a3a” );

We should use LoadFrom method if we know the location and the name of the assembly. For example:

System.Reflection.Assembly myA= System.Reflection.Assembly.LoadFrom(@“c:\myAssembly.dll”);

The property FullName returnsa string representing the assembly identity in the exact format expected by the Load method. To get an AssemblyName reference, we can use GetName method.

We can use LoadFrom method to load an assembly and get the FullName property. After that we can use Load method passing the FullName property.

Once you load the assembly, you can dynamically create objects and invoke methods as shown in the following example:

First we create our component in a Class Library project:

using System;

using System.Collections.Generic;

using System.Text;

namespace MyComp

{

publicclassMyMath : System.IDisposable

{

publicdouble Add(double x, double y)

{

return x + y;

}

bool is_disposed = false;

protectedvirtualvoid Dispose(bool disposing)

{

if (!is_disposed)

{

if (disposing)

{ }

}

this.is_disposed = true;

}

publicvoid Dispose()

{

Dispose(true);

GC.SuppressFinalize(this);

}

~MyMath()

{

Dispose(false);

}

}

}

Then we write a console application to load the assembly MyComp.dll, create an instance of MyMath and then call Add method:

using System;

using System.Collections.Generic;

using System.Text;

namespace UsingReflection

{

classProgram

{

staticvoidMain(string[] args)

{

System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFile("c:/MyComp.dll");

Type comType = asm.GetType("MyComp.MyMath");//asm.GetTypes()[0];

Object comObj = Activator.CreateInstance(comType);

object[] inArgs ={ 10, 20 };

double res = (double)comType.InvokeMember(

"Add", // method name

System.Reflection.BindingFlags.InvokeMethod, // how to bind

null, // binder

comObj, // com object

inArgs // method arguments

);

Console.WriteLine("" + res);

Console.Read();

}

}

}

Marshaling and Remoting

The process of moving an object across a boundary is called remoting, the process of preparing an object to be remote is called marshaling.

A process is a running application. Processes are divided into application domains which in turn are divided into various contexts. Application domains act like lightweight processes.

App domains are secure, versatile, and can be started and stopped independently. They also can provide fault tolerance. If an object crashed in an application domain, it crashes that app domain, but not the entire application.

Application domain uses less resources than a process. Each process has an initial app domain ( the default) and more app domains can be added to this process.

Most program run in a single application domain. If not specified, it would be the default app domain.

An app domain is represented by an instance of the class AppDomain. The static property CurrentDomainreturns the current application domain of the current thread. The static property FriendlyName returns the friendly name of the app domain. The static method CreateDomaincreates a new app domain. The static method Load loads an assembly to the current app domain. The static method Unload removes the current app domain.

App domains are not threads. Multithreading is a mechanism which enable the application to execute more than one task simultaneously. A thread can exist in one application domain at a time. App domains are used to isolate applications and each can have multiple threads running within.

To create a new app domain, call the CreateDomain method as shown below:

AppDomain app= AppDomain.CreateDomain("Course ");

Once you have a new app domain, you can create objects using the CreateInstance method:

ObjectHandle oh=app.CreateInstance(

"MyComp", // assembly name

"MyComp.MyMath",// type name ( class name //with namespace

false,// ignore case

System.Reflection.BindingFlags.CreateInstance,//binding flag

null,// binder

null, // args

null, //culture

null,//activation attributes

null// security attributes

);

Using the CreateInstance create an object in a specific add domain. Using the new keyword creates an object in the current app domain.