September 26, 2006

dotNET Web Application Stress Testing

Stress Testing ASP.NET Web Apps is all about simulation heavy usage and isolating bottlenecks.
There are some Microsoft Tools available, see below. These tools allow you to create scenarios on your website, increase number of users and view the results.

I'll report back with more information when I actually use these tools. For now this is just a placeholder.




Microsoft Stress Test Tool, ACT, Application Center Test. Available from your Visual Studio Enterprise Edition DVD.


Older Stress Test Tool, downloadable from msdn.
http://www.microsoft.com/downloads/details.aspx?
FamilyID=E2C0585A-062A-439E-A67D-75A89AA36495&displaylang=en">


Other useful resources could be Windows Performance Counters. These are Windows information that is available on Processes and Threads running.
You can provide your own applications Performance Counter information be incrementing the Performance counter containers.
The information is Viewable on the Perfmon.exe available on Windows machines.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconruntimeprofiling.asp

September 21, 2006

dotNET AppDomain and Remote Computing (Remoting)

AppDomain

If for some reason you find that you're application cannot load an Type/Assembly at runtime it's usually because assembly lives somewhere different at runtime. For instance the host could do some copying to temporary locations at runtime, this can sometimes cause the references between assemblies to breakdown. So how do you tell the runtime to look somwhere else for the assembly well that's where the AppDomain comes into play.


AppDomain refers to the namespace, space allocated in .NET memory/CLR in which your application is allowed to run.
It's a security thing which prevents applications from cross communicating with each other.

Reasons why you'd want to access the AppDomain can include:
Need to manage the AppDomain i.e. delete or add resources from outside the applications namespace. If you wanted to ensure that certain assemblies for example were to be unloaded from another AppDomain at a certain point, you'd have to setup a new AppDomain and somehow grant it access to the other AppDomain.

AppDomain's have certain properties which are vital to setting them up. A major problem I encountered was forcing an Application to include Assemblies in different path from the one in which it was loaded. This had to be forced by the AppDomain.applicationBase, this was all done with a helper class AppSetup, which allows you to set various properties of an AppDomain before the AppDomain's creation. You must set these properties before creating the AppDomain.


AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
AppDomainSetup appSetup = new AppDomainSetup();
appSetup.ApplicationBase = "file:///C:\\project\\export\\bin;
appSetup.PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory+";C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE\\" ;

AppDomain ad = AppDomain.CreateDomain("Compiling", null, appSetup);

At this stage you have a new AppDomain which will first search the ApplicationBase for Assemblies. The ResolveEventHandler that I register is the actual method that is used to locate assemblies so in you EventHandler you should add code to locate Assemblies in certain paths

private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//Look for assemblies in the current VS project location
string projectDir = Path.GetDirectoryName(BuildTask._presentProjectLocation);
string shortAssemblyName = args.Name.Substring(0, args.Name.IndexOf(','));
string fileName = Path.Combine(projectDir, shortAssemblyName + ".dll");
if (File.Exists(fileName))
{
Assembly result = Assembly.LoadFrom(fileName);
return result;
}
fileName = Path.Combine(projectDir+"\\bin\\"+_mode+"\\", shortAssemblyName + ".dll");
if (File.Exists(fileName))
{
Assembly result = Assembly.LoadFrom(fileName);
return result;
}
//Try the Galaxy export directory
fileName = Path.Combine("C:\\project\\export\\bin\\" + _mode + "\\Tools\\", shortAssemblyName + ".dll");
if (File.Exists(fileName))
{
Assembly result = Assembly.LoadFrom(fileName);
return result;
}
fileName = Path.Combine("C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE\\", shortAssemblyName + ".dll");
if (File.Exists(fileName))
{
Assembly result = Assembly.LoadFrom(fileName);
return result;
}

else
return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;

}

Calling a remote method from a Visual Studio MSBuild BuildTask

It can be tricky to get this right. We came across this when trying to add a BuildTask.

The problem we had was that we were compiling files with our own compiler and we needed to load and unload files at certain times, the way to implement this was through an AppDomain. This temporary AppDomain was required because the output fiiles are first compiled into a dll in the current AppDomain and it cannot be released until the processing of the results are finished. We wanted to access the info in the dll before it was released and so we created a temporary new AppDomain .

Because of this we had to introduce Remote Computing, this is required for one AppDomain to communicate with another. The implementation takes 2 parts, first the class that will be used must inherit from MarshalByRefObject, in our case the Configuration.Compiler class.

To create a remote instance use one of the AppDomain. CreateInstance.... methods. Depending on the location of the assembly containing the MarshalByRefObject class. In our case the Compiler class was in the Configuration.Compiler.dll, which was signed. This meant we could instantiate the object using

Configuration.CompileProxy.Compiler compiler = (Configuration.CompileProxy.Compiler) ad.CreateInstanceAndUnwrap ("Configuration.CompileProxy, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f77dad97b7dc0c2", "Configuration.CompileProxy.Compiler");

But there were problems. This worked fine when the assembly was located in the GAC or in the Visual Studio installation (along with all of it's dependancies),

C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies.

I still haven't found a way to instantiate this with the assembly outside of these locations.

  • Common problems were:
    • Casting the resultant Object from CreateInstanceFromAndUnWrap.. to Type Configuration.CompileProxy.Compiler. Still haven't the resoltion for this, it only happens when I use CreateInstanceFromAndUnwrap or CreateInstanceFrom and then use UnWrap().
    • When CreateInstanceAndUnWrap() is used it creates the Object without issue only if the Configuration.CompileProxy.dll is in the GAC or in the VS installation. I have no soluution for this either.
    • There is an Event which can be handled to resolve the paths to assemblies,

    • ad.AssemblyResolve += new ResolveEventHandler(BuildTask.CurrentDomain_AssemblyResolve);
    • I tried to use this but found that it broke the initial AppDomain too.

I found the solution. The problem is that it is the original AppDomain that is used to resolve Assemblies. The problem was with the UnWrap(), what appears to happen is the UnWrap() tries to match the assembly name just loaded through CreateInstance or CreateInstanceFrom with it's full name, something like

"Configuration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null".

If it can't match it bails out. The solution is to add an EventHandler for the AssemblyResolve Event match the full name with the actual name of an assembly and it's path (I had tried this earlier but it caused an infinite loop, another call I had made must have been causing this!!). The EventHandler is subscribed to the Event of the original AppDomain . Also you should set yourAppDomain's ApplicationBase to the location of your assemblies, and then use CreateInstanceAndUndWrap().

Once you have the object instance you can invoke your method using the ordinary call.

bool result = compiler.Compile(confFileStream, confFileName, out messages);

Also note that there is a tool available in the .NET Frameword for debugging assembly binding and resolving, it's called the Fusion Logger, Fuslogvw.exe, it allows you to view what the CLR is doing at runtime with the assemblies.

To run fuslogvw.exe you must install the .NET SDK and then run it from here
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0>Fuslogvw.exe

Fuselogvs.exe CodeProject Tool to debug AppDomain Assemblies
AppDomain Class (msdn)

Suzanne Cooks .NET CLR Notes - Executing Code in Another AppDomain

Suzanne Cooks .NET CLR Notes - Choosing a Binding Context

AppDomain.CreateInstanceAndUnwrap(..) vs AppDomain.CreateInstanceFrom

Why does AppDomain.CreateInstanceAndUnwrap(..) work and AppDomain.CreateInstanceFrom(...).UnWrap doesn't?

Remote Computing and Marshaling (MarshalByRefObject)
Yariv Hammers - Calling Remote Objects - Basic Concepts.
Yariv Hammers - Create a Simple Client/Server App with Remoting..

I've mentioned in the AppDomain about marshalling and inheriting your class from MarshalByRefObject, now I'll describe what this actually means and does.

Marshaling
This is the related to the Serializing and De-Serializing of objects, this term is particular to Remote Computing. As I've described in another post Serializing of objects is creating a stream version of your objects data.
In Remote computing objects can be passed from one application to another by serializing the object on the sender side and de-serializing on the receiver side, Marshaling and Demarshaling.

In .NET this is achieved by making your class inherit from MarshalByRefObject. Now when you pass objects from your class to another AppDomain they will be marshalled before passing. The other AppDomain will then Demarshal the parameters when received.

September 20, 2006

dotNET Serialization (XmlSerializer)

Serialization is the process of representing you Object in the form of text.
This is a handy way to save out your Object structure to a file.
The XML version is XmlSerializer, this creates an XML file structure of your Object. It will parse out all the public properties and save to XML.

You can make your objects Serializable by simply adding the Serializable Attribute to each of your objects, when you call Serialize on that Object it and all of it's Child and Associated Objects which also have the Serializable Atribute will also be Serialized
[Serializable]
public class BaseballPlayer
{
[...]
}
To invoke Serialization on an Object you need a Formatter and a Stream. Or you can use XmlSerializer to perform the Serialization.
see XMLSerializer and not expected type... (codeproject)
Stream str = File.OpenWrite(filename);
System.Runtime.Serialization.Formatters.Soap.BinaryFormatter formatter =
new System.Runtime.Serialization.Formatters.Soap.BinaryFormatter();
formatter.Serialize(str, bp);
str.Close();
The BinaryFormatter's output is binary, so the output is illegable and compacted, to create a readable format use the SoapFormatter. There is a problem with the SoapFormatter however, it cannot handle non generic types, such as your own types of containers, it can only handle .NET types including Lists. So if your Objects contain your own types of containers you must make them serializable, How?

At runtime is XmlSerialization is requested by some process ( a webservice for example requires Objects to be Serialized, SOAP), then the Object (maybe the Type inside the assembly) will be XmlSerialized at runtime, resulting in a temporary file named .XmlSerializers.dll being created.
To create an XmlSerializer version of your file use sgen.exe, it's a Visual Studio Tool.

C:\bin\debug\Tools>"C:\Program Files\Microsoft Visual Studi
o 8\SDK\v2.0\Bin\sgen.exe" /a:Configuration.CompileProxy.dll /o:C:\server\bin
Microsoft (R) Xml Serialization support utility
[Microsoft (R) .NET Framework, Version 2.0.50727.42]
Copyright (C) Microsoft Corporation. All rights reserved.
Serialization Assembly Name: Configuration.CompileProxy.XmlSerializers, V
ersion=1.0.0.0, Culture=neutral, PublicKeyToken=null.
Generated serialization assembly for assembly C:\bin\debug\
Tools\Configuration.CompileProxy.dll --> 'C:\server\bin\Configuration.CompileProxy.XmlSerializers.dll'.

XMLSerializer (msdn)

Serialization in .NET (codeguru).

September 18, 2006

MSBuild

MSBuild Team Blog.
MSBuild documentation (msdn)
BuildTask creation
MSBuild used by VS projects to build items. You can add build tasks to your Project file, either by directly adding to the .proj file or by creating .targets files with the task within and then adding this .targets file to your project file using the include option. The BuildTask can do anything you wish but the format which you call it is basically the same.
To use a build task you must include the file that contains the BuildTask functionality. The BuildTask itself is just a class that extends Microsoft.Build.Utilities.Task.
Compile it into a dll and include the dll in your project file with the UsingTask . The AssemblyFile points to the location and name of the task's assembly, AssemblyFileName can also be used but only requires the file name, this means the file must be in the GAC or in the installation of .NET.

<pre> <usingtask taskname="SetupUtils.RegistryTask" assemblyfile="..\Setup Util\bin\Debug\Setup Util.dll">
<target name="EnvSetup"></target></usingtask>
</></a><usingtask taskname="SetupUtils.RegistryTask" assemblyfile="..\Setup Util\bin\Debug\Setup Util.dll"><target name="EnvSetup"><registrytask variable="RegistrySetting" registrykey="Software\\Solutions Ltd\\Installation">
<output taskparameter="RegistryValue" propertyname="RegistryKeyValue">
</output>

Some other useful formats of the BuildTask are,

</a><usingtask taskname="SetupUtils.RegistryTask" assemblyfile="..\Setup Util\bin\Debug\Setup Util.dll"><target name="EnvSetup"><registrytask variable="RegistrySetting" registrykey="Software\\Solutions Ltd\\Installation">
<output taskparameter="RegistryValue" propertyname="RegistryKeyValue">
</output>

it can take parameters and also return strings
which can then be used to set other variables in the project file.

<message text="The result is : $(RegistryKeyValue)">
</message>
</registrytask></target></usingtask></pre>

The above example sets the RegistryKeyValue variable to the Property RegistryValue found in the BuildTask itself, see below, the function with the Output property indicates to MSBuild that this is an output. So the Output method using the TaskParam shown above and provide and PropertyName to hold the result.
        using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Win32;


namespace SetupUtils
{
///
/// Get or Set the Registry Entries
///

public class RegistryTask : Task
{
private string _variable;//not significant
private string _registryKey;//the Registry Key ,
e.g. "Software\Solutions Ltd\Installation"
private string _registryKeyValue;//the value of the _registryKey.


[Required]
public string Variable
{
get { return _variable; }
set { _variable = value; }
}


[Required]
public string RegistryKey
{
get { return _registryKey; }
set { _registryKey = value; }
}


[Output]
public string RegistryValue
{
get { return _registryKeyValue; }
set { _registryKeyValue = value; }
}


public override bool Execute()
{
if (_registryKeyValue != null)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(_registryKey);
if(key != null)
key.SetValue("Default",
_registryKeyValue, RegistryValueKind.String);
else
Log.LogMessage(MessageImportance.Normal,
"No key by that name : " + _registryKey);
}
else
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(_registryKey);
if (key.GetValue("Default") != null)
{
_registryKeyValue = (string)key.GetValue("Default");
Log.LogMessage(MessageImportance.Normal,
"the variable value is : "
+ _registryKeyValue);
}
}
return true;
}
}
}

There is a also a third party tool which I have found very useful for Zipping files into a single zip file, the MSBuild
Zip utility is not usefult enough. It can be downloaded from an opensourse project MSBuildTasks. The download
provides the dll with the functionality, a targets file to import into you project file to point to the dll and a
help file. In my case I used
<target name="All">
<calltarget targets="Build">
<calltarget targets="Zip">
</calltarget>
</calltarget>
</target>

<itemgroup>
<zipfiles include="Templates\MyTemplate.vstemplate">
<itemgroup>
<target name="Zip">
<zip workingdirectory="Templates" files="@(ZipFiles)" zipfilename="Templates\MyDevenv.zip"><copy sourcefiles="@(ZipToCopy)" destinationfolder="">

<output taskparameter="CopiedFiles" itemname="SuccessfullyCopiedFiles">
</output>
<itemgroup>
<zipfiles include="Templates\MyTemplate.vstemplate">
<itemgroup>
<target name="Zip">
<zip workingdirectory="Templates" files="@(ZipFiles)" zipfilename="Templates\MyDevenv.zip">




In order to direct the output messages of the BuildTask to the correct tab in the output console of
Visual Studio you need to follow a particular string format, Errors get filtered to the Error List in the Console window.

MSBuild / Visual Studio aware error messages and message formats

Delegates

Delegates

Delegates are similar to C++'s function pointers, as it says on the tin a pointer to a function.
The beauty of delegates and function pointers is that you can throw it around in different classes without that class having knowledge of the object to which the function belongs.

Here's a simple example:


declare your delegate in some class.

public delegate void DelegateFunc();// you must have a func with the same signature


now create a function in another class with same return type and same parameters.

class DelegateClass
{
public static void TheRealDelegateFunc()
{
}
}

now call the delegate from the first class


public delegate void DelegateFunc();// you must have a func with the same signature

static void Main(string[] args)
{
DelegateFunc df = new DelegateFunc(DelegateClass.TheRealDelegateFunc);
df.Invoke();

}

Notice the Invoke() function, this is required to run the function.


http://en.csharp-online.net/index.php?title=CSharp_Delegates_and_Events



System.Delegate and MulticastDelegate
The System.Delegate class also has to very useful methods which allow to you store delegates for invokation later. System.Delegate.Combine(..) and System.Delegate.Remove(..).
Combining 2 or more delagates allows invokation later, the Combine method returns a MulticastDelegate instance which can simple be invoked by calling the instance with the correct parameters, this then calls all the delegates with the matching signature that have been added using the Combine method.