December 06, 2006

dotNET - Use app.config ApplicationSettings and UserSettings

When using Settings in an Assembly or .exe you can use the Settings Designer to generate a config file using Settings. The Settings Designer provides a wrapper class which allows you to provide defaults and access the config data using Properties.
But what if you're not working inside that Assembly or .exe? this presents a problem.
If your loading the Assembly externally and want to access that Assembly's .config file you'll probably wish to use something in the System.Configuration namespace... unfortunately it's not of much use if you've created the .config file from the Settings Designer in Visual Studio!!
This is because the Designer creates Sections and ApplicationSettings and UserSettings, the System.Configuration namespace does not provide a method to access these (it has a method to access AppSettings which are a different thing.
Below I've written a workaround which locates the app.config and accesses the ApplicationSettings and UserSettings using XML instead of System.Configuration.

_server = GetAssemblySettingOrDefault(Path.Combine("C:\temp\MyAssembly.dll"), "serverLocation", "http://localhost/mydefaultserver/mydefaultserver.asmx");



Return a key/value list of ApplicationSettings and UserSettings for a given .exe's of .dll's .config file.


public static KeyValueConfigurationCollection GetAssemblySettings(string assemblyPath)

{
Configuration config = ConfigurationManager.OpenExeConfiguration(assemblyPath);

XmlDocument dom = new XmlDocument();
dom.Load(config.FilePath);

//UserSettings and ApplicationSettings
KeyValueConfigurationCollection returnList = new KeyValueConfigurationCollection();

string[] settingsTypes = { "applicationSettings", "userSettings" };
foreach (string settingType in settingsTypes)
{
XmlNode node = dom.SelectSingleNode("//configuration//" + settingType);
if (node != null)
{
try
{
if (node.HasChildNodes)
{
foreach (XmlNode childNode in node.ChildNodes)
{
if (childNode.HasChildNodes)
{
foreach (XmlNode settingNode in childNode.ChildNodes)
{
if (settingNode != null)//the Settings node
{
if (settingNode.Attributes.Count > 0) //there should be at least one attribute
returnList.Add(settingNode.Attributes[0].Value, settingNode.InnerText);//the setting name and the setting/value
}
}
}
}
}

}
catch { throw; }
}
}
return returnList;
}

// Get the value of the Assembly ApplicationSetting or UserSetting from the key.
// If the key does not have a value then return the default supplied by the caller.

public static string GetAssemblySettingOrDefault(string assemblyPath, string assemblySettingKey, string assemblySettingDefaultValue)
{
string result = assemblySettingDefaultValue;
KeyValueConfigurationCollection settings = GetAssemblySettings(assemblyPath);
if(settings != null)
{
KeyValueConfigurationElement key = settings[assemblySettingKey];
if(key != null)
result = key.Value;
}
return result;
}

November 29, 2006

Windows Miscellaneous

Virtual PC
Creating a Virtual PC using another machines Virtual Hard Disk
Make a copy of the other machines .vhd file.
Copy to the local machine and point the new Virtual PC to the .vhd.
SID will have to be run on the new Virtual PC in order to change the name of the machine, as it will still have the name of the original machine the vhd was taken from.

http://www.microsoft.com/technet/sysinternals/Security/NewSid.mspx

HTML DOM Inspector
http://www.sharewareconnection.com/download-ie-dom-inspector-from-sharecon.html

November 14, 2006

dotNET - VS 2005 Web Deployment Projects + Installer (MSI) creation

You've got your Web Project in Visual Studio and you want to create a way to provide it as an installation.
There are 2 ways to do this:
1. Create a Web Deployment Project from your Web Project and then use the output of this as the input to another project, a Setup Project.
After you've achieved this you'll have an MSI installer file which has configurable elements, these configurable elements will be dictated by yourself when creating the Web Deployment Project and the Setup Project.
2. Create a WebSetup project from your Web Project.
After you've achieved this you'll have an MSI installer file.

Option 2 is the simpler option.
The difference between the 2 options is that the first provides extra control using the Deployment project, such things a MSBuild and assembly type deployment.


If you choose option 1 then:
  • You can quickly create a Web Deployment Project by right-clicking the Web Project in the Visual Studio Solution Explorer. This will copy the contents of your Web Project into the new Deployment Project. See the links below on how to customise the settings.
  • The Setup Project uses the Web Deployment Project, this is achieved by adding the Web Deployment projects output as a reference, Right Click on the Setup Project...
  • Notes:
  • I noted during the Web Deployment Project creation that;
  • Changing the Project Properties does not always apply e.g. I changed the Property Pages->Deployment section to "appsettings=appsettings.config", this indicates the appsettings section of the Websites web.config should be overridden with that in the appsettings.config file in the source Web Project. But the appsettings is case-sensitive, I fixed it but it still did not apply resulting in a compilation error, I had to edit the project file itself using the VS editor. The contents of the appsettings.config file is the complete appSettings section, including the appSettings tags.
  • The appSetting file is located in the original Web Project.
  • Using appSettings=appsettings.config in the Web Deployement Project's Property Pages->Deployment section it overrides the appSettings section.
If you choose option 2 then:
  • This is a much simpler solution and really just copies the contents of your Web project into an exe or msi file for later installation.
  • Create a Web Setup project from the File->New Project dialog, under Setup and Deployment.
  • Add the Web site project's Output as a reference in the WebSetup project.

For both option 1 and 2 you'll need to create some sort of Setup project, either a Setup project (Option 1. which uses the output of the Web Deployment project) or a Web Setup project (Option 2. which uses the Web project directly).
For more on both types of Setup project and how to use the user input see the article later in this blog dotNET - Setup Programs Installer creation using VS2005

Using Web Deployment Projects with Visual Studio 2005 (msdn)
ScottGu's Blog - VS 2005 Web Deployment Projects
Modifying Web.Config during Website Installation (AspAlliance)

November 07, 2006

Cookies and FormsAuthentication

Cookies

Cookies are simply a file stored in the client machine which are sent up and down to and from the server with every Request and Response.

The Cookie is used to store some client information such as details of their past session. It allows the Client to return to a webpage and have information already available to them without having to start from scratch.
The Cookie is first sent down from the Server and is stored somewhere on the Client's hard-drive.
It's up to the Web Application developer to do the Cookie processing on the Server side. The Cookie can be accessed from the Request as the Cookie is a property of the HttpRequest, Request.Cookie["cookiename"];

One problem I've encountered with Cookies is that all the cookies associated with your application get Posted from the Client on each Request, this adds to the amount of data sent as you can imagine. There is a solution however, in order to ensure a Cookie is only sent from Client to Server when a certain page is open you must create the Cookie with it's path set to that page;
HttpCookie rememberLogin = new HttpCookie("rememberLogin", rememberLogin.Expires = DateTime.Now.AddDays(5);
rememberLogin.Path = Request.Path;
Response.Cookies.Add(rememberLogin);

Codeproject.

Authentication

Who Are You?
There are 2 main types Windows and Forms.

Windows Authentication

This will use the clients credentials i.e. their actual windows login that they are presently using, allowing your server side app to examine who the client actually is.
Note that the client will usually have to pass their credentials onto the Server, this can be done in code adding their credentials, System.Net.CredentialCache.DefaultCredentials, to the HttpRequest with the following:
for a .NET Remoting call:
IDictionary channelProperties = ChannelServices.GetChannelSinkProperties(_remoteObject);
channelProperties["credentials"] = System.Net.CredentialCache.DefaultCredentials;

For all of this to work you muse have "Integrated Windows Authentication" (only) enabled on the Server or a subdirectory within the Server.
If you also have "Anonymous Access" enabled then Windows Authentication will not work, if you must have "Anonymous Access" enabled as well for some reason then follow these 3 steps:
1. Create a subdirectory and set it's Security settings to "Integrated Windows Authentication" e.g. "MyIntegratedDir". This subdirectory will then work as you'd expect and you can use Windows Authentication on this directory.
2. Add an entry to the Web.config to tell IIS Security to permit Anonymous users access to the particular directory.
<location path="MyIntegratedDir">
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</location>
3. Place you Custom Authorization code within this directory i.e. probably in an aspx page

FormsAuthentication
FormsAuthentication is not directly related to Cookies but they can work together.

You can access the FormsAuthentication information from code using the FormsAuthenticationTicket.
By querying this object you can redirect etc to other pages depending on roles etc.
The FormsAuthenticationTicket object can then be passed to the Cookie constructor in order to save the information, this means the Client does not have to provide the information on each page, the Cookie is sent up and down to the Server ensuring the Client has access.
codeproject.


Authorization

In the web.config you can specify what groups or who you wish to allow or deny from your website, you can break your website down into subfolders, this is known as Authorization i.e. What you are allowed to do.

dotNET - Http traffic debugging using Fiddler

So you want to view the Http traffic between client and server. Fiddler's your man.
You can view the traffic on requests including Cookies and Cached data.
For more see msdn and fiddler.com.

November 06, 2006

Setup Programs Installer creation using VS2005

Setup Programs Installer creation using VS2005
Getting Started with Setup Projects (SimpleTalk).
Visual Studio Setup Projects and Custom Actions (Simple Talk).
Updates to Setup Projects (SimpleTalk).

To create an Installer using Visual Studio you must create a Setup Project. A setup project contents are files and outputs of other projects in the solution. The Setup Project template can be found in the Visual Studio New Project dialog under Other Projects->Setup and Deployment->Setup Project.


Tip! To debug installation or just see what's happening in the background and view system variable values use the msiexec logger, it logs everything that's happening on installation, it can also be used for uninstall
install:
msiexec /i yourinstaller.msi /l* yourinstaller.log
or verbose
msiexec /i yourinstaller.msi /l*v yourinstaller.log

uninstall:
msiexec /uninstall yourinstaller.msi /l* yourinstaller.log
or verbose
msiexec /uninstall yourinstaller.msi /l*v yourinstaller.log

Description of how to create a Setup Project
Deploying Windows Applications (Charp Onlline .NET).

You'll see that the Setup Project (note there's also a WebSetup project template) supplies the dialogs etc for user info entry, I don't think there's a way to override this. The dialogs allow limited user input. The user input from the dialogs textfields is available to you through Properties, I'll talk about how to access them now.
Setup Project Property Reference (msdn).
This is all done for you but there are a couple of things to look out for, as always if you wish to do something different it's tricky. For example if you wish to get some information on the Installation you must use a Custom Action.


Updating/Patching the installation
Updates to Setup Projects (SimpleTalk).
It doesn't appear that this is implemented all that well with Visual Studio setup projects, they don't have the power.
The SimpleTalk link gives instructions on the ways to implement update packages but it does mention that patching (just updating certain files) is not implemented, it's a full install/reinstall or nothing, even the repair does this.

Merge Modules
Installing Shared Components using Merge Modules (msdn).
The contents of the Setup Project can be broken up into Merge Modules. The Merge Modules contain Components, the components contain your installer items.
The Merge Modules are a useful tool if you wish to add contents to your installer from other resources such as projects outside of your current solution, if you wish to import outputs from a project in a location outside of your present solution then create a new Merge Module project in the other solution and then add the Merge Module to the current Setup Project.

MSBuild and Setup Projects

Word of warning on Setup Project (.vdproj). MSBuild will not build these type of projects. The result is a warning in MSBuild ... and the contents (the Outputs of other Projects which the Setup uses) are not updated, it could install older versions of files than you had hoped.

One solution would be to Build the Setup project manually after running MSBuild.

Another solution is to tell devenv to explicitly build the Setup project
There are 2 ways to do this:
  1. On the command line, e.g in your build script with
  2. In another project file tell devenv to build the project using devenv


To Force an uninstall try this
MsiExec.exe /I installer.msi REINSTALLMODE=voums REINSTALL=ALL
installer.msi is the name of your installer. The Repair/Remove dialog will appear and you can then Remove.

November 01, 2006

Miscellaneous

New Assignment instead of Virtual/Override
The "new" keyword can be used with methods, it provides a type of inheritance similar to polymorphism.
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
ChildClass cc = new ChildClass();
bc.Foo();
bc.Bar();
Console.WriteLine("=======================");
((BaseClass)cc).Foo();
((BaseClass)cc).Bar();
Console.WriteLine("=======================");
cc.Foo();
cc.Bar();
Console.WriteLine("=======================");
Console.ReadLine();
}
}

class BaseClass
{
public void Foo() { Console.WriteLine("BaseClass.Foo"); }
public virtual void Bar() { Console.WriteLine("BaseClass.Bar"); }
}

class ChildClass : BaseClass
{
new public void Foo()
{
Console.WriteLine("ChildClass.Foo");
base.Foo();
}
public override void Bar()
{
Console.WriteLine("ChildClass.Bar");
base.Bar();
}
}
Output:
BaseClass.Foo
BaseClass.Bar
=======================
BaseClass.Foo
ChildClass.Bar
BaseClass.Bar
=======================
ChildClass.Foo
BaseClass.Foo
ChildClass.Bar
BaseClass.Bar
=======================
In the above the use of new in the method signature indicates that we the ClildClass wishes to override the BaseClass method Foo().
As we can see from the output the call to
((BaseClass)cc).Foo();
results in
BaseClass.Foo
as we would expect. You could use Virual/Override to do the same thing. But note in the above case we use DownCasting, and in this case the Virtual/Override still calls the ChildClass.Foo and the new assignment version does not, this is suprising to me at least as I would have thought the opposite were true.



Calling one Constructor from another with CSharp

This allows us to create an instance with either of these 2 overloads.
Note that if we use the first overload then the second parameter is null, usually a check would be done in the second overload for null and some default applied
public MyClass(string param1) : this(param1, null)
{
}
public MyClass(string param1, string param2)
{
if(param2==null)
param2 = "default";
}
These could also be called vice versa of course
public MyClass(string param1)
{
_param2 = "default";
}
public MyClass(string param1, string param2) : this(param1)
{
_param2 = param2;
}


Request a Web Page from outside a Web Application

using System.Net;
using System.Xml;
using System.IO;

namespace UrlCall
{
class Program
{
static void Main(string[] args)
{

string url = "http://localhost:3703/ServerProject/Cookie/GetCookie.aspx";

HttpWebRequest myWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
myWebRequest.Method = "GET";
// make request for web page
HttpWebResponse myWebResponse = (HttpWebResponse)myWebRequest.GetResponse();
StreamReader myWebSource = new StreamReader(myWebResponse.GetResponseStream());
string myPageSource = myWebSource.ReadToEnd();
myWebResponse.Close();

}
}
}

Reflection, how the metadata works
CodeProject has an explanation of the internals of a .NET assembly.

Training/Certification
dotNetSlackers has a good description of the .NET Certification available.

Tools

.NET Framework Tools (msdn).
CFF Explorer (Tool to investigate the internals of a .NET assembly).

Fix ASP.NET

If you've installed a new version of .NET you'll have to register it, it's required for ASP.NET to use the correct version
aspnet_regiis.exe -i
Depending on where you call this from will determine which .NET gets used with ASP.NET
e.g.
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis -i
Errors that this may fix are
"Some of all identity References could not be translated"
"iis metadata access rights.

GAC (installing assemblies in the GAC)
The GAC is a location on Windows where Assemblies can be stored, the idea is that all applications can access this one assembly. It's also versioned. The GAC contents can be viewed at C:\Windows\Assembly.
To install your assembly in the GAC you can use to methods
The exe from the .NET SDK
C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\gacutil.exe /i
or the Visual Studio SDK
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe /i
or programmically using the GacInstall class
try
{
System.EnterpriseServices.Internal.Publish gac = new System.EnterpriseServices.Internal.Publish();
gac.GacInstall(assemblyName);
}
catch (System.Security.SecurityException se)
{

}

Assembly Code Analysis Tool (FxCop)
FXCop is a MS Tool which analyzes you Managed Code by loading your assembly, reading the manifest and analysing the MSIL in the CLR.
FxCop bried description (TechRepublic)
FxCop (msdn)


Download from gotdotnet.com



Http debugging tool

So you want to view the Http traffic between client and server. Fiddler's your man.
You can view the traffic on requests including Cookies and Cached data.
For more see msdn and fiddler.com.

Some useful dotNET methods etc

  • Ref and Out
  • Use these keywords to pass a reference to another method so that it the reference itself can be changed. All objects are passed by reference in C#, meaning if you wish another object to change values in another object you simply pass the objects reference (the variable name) to the method as normal.
  • Class Passer
    {
    List messages = new List();
    Receiver r = new Receiver();
    r.Method(messages);
    }
  • Class Reveiver
    {
    void Method(List messages)
    {
    message.add("I'm adding a new item to the Passers member messages, this affects the original");
    }
  • However if you want another method or object to change the instance itself, I mean new-up a new memory location with your original reference then you use Ref.
  • The difference between Ref and Out is that Ref is initialized by the passing object and Out is initialized by the receiving object e.g.
  • Class Passer
    {
    List refMessages = new List();
    Receiver r = new Receiver();
    r.RefMethod(ref refMessages);

List outMessages; //not initialized here in the passing object
r.OutMethod(ref refMessages);
}


    Class Reveiver
    {
    void RefMethod(ref List refmessages)
    {
    refmessage.add("I'm adding a new item to the Passers member messages");
    }
void OutMethod(out List outmessages)
{
List outmessages = new List();
outmessage.add("I'm adding a new item to the Passers member messages");
}

}



  • To determine if it's a web app or a windows app use
    • System.Web.HttpContext.Current;
    • If null it's a windows app.
  • TryParse can now be used to determine if 2 values are equal.
    • It can presently be used for int, double, DateTime ....
    • There are 2 params, the value your comparing to and the out which is the result boolean value which is set.
  • Using statement
    • If you are using an Object which implements the Dispose/Inherits from IDisoposing then you can use Using to ensure the object is GC'd after use.
e.g. instead of StopWatch sw = new StopWatch try
using(StopWatch sw = new StopWatch try)
{....
}//sw is deleted here.


  • Get the name of the current method at runtime, useful for printing:
System.Reflection.MethodBase mb = System.Reflection.MethodBase.GetCurrentMethod();
Get the name of the Current Method
string currentMethod = mn.Name;
Get the Current Class name
string currentClassName = mb.DeclaringType.Name;
Or Get a Method at a particular location in the stack: System.Diagnostics.StackFrame sf = new System.Diagnostics.StackFrame(0, true); //To get the calling method name, use 1 instead of 0.
string currentMethodName = System.Reflection.MethodBase mb = sf.GetMethod();
string methodName = mb != null ? mb.Name : "nothing found";
  • Creating Disposable Objects
  • Visual Studio Project Macros/Variable/Properties
  • Here's a useful static method for dumping messages (debugging) to a file:

  • public class DebugWriter
    {
    public static void WriteDebugToFile(string message)
    {
    string path = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "DebugFile.txt"));
    StreamWriter sw = null;
    if (!File.Exists(path))
    {
    using (sw = File.CreateText(Path.GetFullPath(Path.Combine (Environment.CurrentDirectory, "DebugFile.txt"))))
    {
    }
    }
    using (sw = File.AppendText(path))
    {
    sw.WriteLine(message);
    sw.Close();
    }
    }
    }



October 27, 2006

dotNET Project Template and Addin Creation

Project and Item Templates
Create Reusable Project and Item Templates for the development team.

Project Template Creation
Creation of a project or item template is pretty straight forward.

Use the File->Export Template to create the template, the wizard will ask you which Project you wish to base your Template on, this will result in the contents of that Project being added to the Template.
Note that depending on the type of Project you select will determine where the Template appears in the File->New Project dialog.
i.e. If you base your Template on a Website Project in VB then the Template will appear in the File-New Website and under the VB section in the File->New Project dialog.


Create a project like the one found at
http://msdn.microsoft.com/msdnmag/issues/06/01/CodeTemplates/default.aspx.

The Template is just a zip file with an extra xml file within, the xml file describes what to add to the project when a user uses File->New Project.

If you wish to generate Project Templates at build time from another project it can be done through MSBuild. I've written a description of this in the MSBuild Post, ZipProject is the MSBuild task.


Editing the Contents of the Template File
The File->Export Template will create the template for you. When the user uses this template they are not prompted for anthing besides the Project name, what if you wish for the user to supply some additional information when creating a new project using your template? It's not very easy...
Basically you have to create a seperate class which is a type of Form, it's an implementation of IWizard. The assembly generate needs to be registered in the GAC and then a reference to this Assembly added to your Template file, see this msdn link:
http://msdn2.microsoft.com/en-us/library/ms185301.aspx.
Note that one of the steps is the Signing the Assembly, use the VS feature in the Project Properties for this. And then run C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0>gacutil /i
C:\temp\WizIDE\WizIDE\bin\Debug\WizIDE.dll

Now we have installed the assembly. After the assembly is installed you should use the File->Export Template. After that youwill need to edit the XML file, so unzip the file at and edit the xml file Add the assembly name details which were generated with the Project->Properties->Signing feature, to see what the value is used gacutil again
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0>gacutil /l WizIDE

And add the result to the xml file after , that is outside of TemplateContent, like the following:
WizIDE, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=1d20aa67bdcd2085,
processorArchitecture=
IDE.IWizardImplementation

Now Rezip and open a new project of this type. If you change the assemble functionality then maybe a reinstall is required C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0>gacutil /uf WizIDE


Web Application Template Creation
The template is generated in the same manner as the project template, select your website project and use File->Export Template.
As with the project template, templates can be created at build time from your project using MSBuild, see my MSBuild post, ZipProject is the MSBuild task, you'll see that the Web application template is a bit more difficult to configure from MSBuild, there are alot of workarounds to include subfolders in the resultant zip file.


String Substitution in Templates
Project Template also provide the ability to substitute strings for strings in the files included in the Template.
Your .template file which is created for you (and included in the .zip file) contains a list of all files in the Template. It also contains some properties of each file including a boolean which tells the Template installer to substitute certain strings when the Template is used.
e.g.
(open tag)
ProjectItem ReplaceParameters="true" TargetFileName="app.aspx">app.aspx
app.aspx.cs
$safeprojectname$ gets replaced with the name you give to your project.
e.g.
The original name of your project was "Server".
You generate a Project Template from Server.
The Template Generator sets all the file entries in the template file to have substitution on.
The Template Generator sets replaces all entries of the word "Server" in all of those file with the placeholder
$safeprojectname$.
You create a new Project using the Template and name it "MyNewProject".
When you create a Project with the Template the placeholder
$safeprojectname$ is replaced with the name of your project.

in the asp.aspx.cs file
using MyNameSpace.Server; is replaced with MyNameSpace.MyNewProject;

Original app.aspx.cs in Project named "Server".
using System.Collections.Generic;
using MyNameSpace.Runtime;
using MyNameSpace.Server;

The app.aspx.cs generated and add to the Template"Server".
using System.Collections.Generic;
using MyNameSpace.Runtime;
using MyNameSpace.
$safeprojectname$;

The new app.aspx.cs in new Project named "MyNewProject".
using System.Collections.Generic;
using MyNameSpace.Runtime;
using MyNameSpace.
MyNewProject;


http://msdn2.microsoft.com/en-us/library/eehb4faa(VS.80).aspx

Other properties which can be substituted are:
msdn Template Parameters.
msdn (
Modifying or Creating a Visual Studio Project Template).

Addin Creation
Addin Creation To create custom controls, menu items etc use the Addin. There is an Addin Project in VS, create a new Addin Project from scratch and compile. To register the new addin choose Tools->Addin Manager, select the new Addin from the list and restart VS, the Addin Tools items now appear in the menu. The Addin’s .addin file has been copied to
C:\Documents and Settings\\My Documents\Visual Studio 2005\Addins

http://msdn2.microsoft.com/en-us/library/80493a3w.aspx
Addin examples can be downloaded from
microsoft


Item Template Creation
In order to add a custom item to the New Item command we have to create another template and Item Template. I have developed this in particular for the Entity creation.
It is virtually identical in makeup to the Project Template but with a different form for data entry. The installation process is the same as the Project Template earlier except this time you create an Item Template instead of a Project Template when using File->Export Template.

Summary
When you create a Template the template .zip file gets copied into 3 locations where VS will detect them
The original location:
C:\Documents and Settings\me\My Documents\Visual Studio 2005\My Exported Templates
the Visual Studio Project Template location (This is an optional step in the Export Template Wizard):
C:\Documents and Settings\me\My Documents\Visual Studio 2005\Templates\ProjectTemplates
and also a cache location
C:\Documents and Settings\me\Application Data\Microsoft\VisualStudio\8.0\ProjectTemplatesCache
The Cache location may cause confusion, if you no longer want to use the Template and decide to delete it you must also delete from the Cache location.


Problem here when referencing the DLLs, because we have made the Templates “Strongly Named” we cannot reference the “Weakly Named” assemblies. Solution?? Currently there are 3 projects. WizIDE which creates a Project Template, a dll, WizIDE.dll which is added to the Project Template as the Zip file WizIDETemplate.zip. IDEAddin, creates a DLL, IDEAddin.dll, this is is installed through the VS Addin Manager, it is added as an .addin file to the
required, presently it adds a new item to the Project menu which does nothing right now. EventItemTemplate, creates a DLL, EventItemTemplate.dll, this is installed in the same manner as the Project Template at C:\Documents and Settings\\My Documents\Visual Studio 2005\Addins.
Creates the extra menu items which maybe
C:\Documents and Settings\\My Documents\Visual Studio 2005\Templates\ItemTemplates\EventItemTemplate.zip
.
This provides the functionality to create new Entity through a wizard, New Item dialog now contains another item type, EntityItemTemplate which launches a wizard and prompts for Entity parameters.




Installing the Project and Item Templates
If you create your Project and Item Templates using MSBuild from your source projects using ZipProject and ZipItem then the templates will be installed for you by MSBuild into the correct location (note a copy of these files can be found in your source projects obj/Debug or whatever directory). But of course you'll want to install these templates on a clients machine using an installer of something equivelant., the solution is to copy the files into the Visual Studio installation from your installer using a Custom Action (the custom action is a project you create, it inherits installer and can be called from the installer). You'll also need to reset the Visual Studio Cache, this can be done from the Custom Task code too

System.Diagnostics.ProcessStartInfo ps = new System.Diagnostics.ProcessStartInfo(Path.Combine(vsDevenv, "devenv.exe"));
ps.Arguments = @"/setup";
System.Diagnostics.Process.Start(ps).WaitForExit(10000);//give the process a max of 10sec to finish

October 24, 2006

dotNET Custom Controls and Resource Scripts

Custom Controls are Web Controls, (TextFields, Labels etc) which are customized by you.

The Custom Controls can then added to your website by adding the assembly containing the Custom Control or used through Visual Studio ASPX editor by created adding the Custom Control to the ToolBox (this is done by Right-Clicking the ToolBox and selecting Choose Items... then select the locate of the Assembly containing the Custom Control.

An example of a very simple Custom Control implementation can be found here
Simple Custom Control (msdn)


Additionally you can embed some of you JScript code in a .js file instead of in the aspx page itself. This js file should be added to you Custom Control project as an Embedded Resource (This means the JScript code is embedded in the resultant assembly. When this assembly is referenced by a website project it will be able to access the JScript functionality (??).
To add the js file add it to the Custom Control Project as a Resource.
Add a new Resource file to the Project.
Add you js file to the project. Set the Property of the js file, "Build Action" to "Embedded Resource".
Add the js file to the Resource file using the Resource Designer, Choose Add Existing Item.. from the menu at the top of the Resource Designer.
Add a Line to the AssemblyInfo.cs file,
first include:

using System.Web.UI;

to the top of the file
[assembly: WebResource("WebControlLibrary1.Resources.JScript1.js", "text/javascript", PerformSubstitution = true)]


Now to enable accessing the JScript contents from and ASP.NET file you must Register it with your Custom Control, do this in the OnPreRender Overload method using

protected override void OnPreRender(EventArgs e)
{
Page.ClientScript.RegisterClientScriptInclude(this.GetType(), "jscriptcontrol", Page.ClientScript.GetWebResourceUrl(this.GetType(), "WebControlLibrary1.Resources.JScript1.js"));
base.OnPreRender(e);
}


Now rebuild. Your JScript file is now embedded in the assembly and can be accessed from ASP.NET using when you add the Custom Control to the aspx page using

(open bracket)
cc1:WebCustomControl1 ID="WebCustomControl1_1" runat="server"

(close bracket)

Adding JScript files and other resources to an assembly ans accessing from ASP.NET
Adding and Accessing Embedded Resources
Adding Client Scripts to ASP.NET
http://msdn.microsoft.com/msdnmag/issues/06/05/CuttingEdge/default.aspx#S6

To test your embbedded resource is actually correct:
Drag and drop the Custom Control which references the JScript into a new aspx page.
Publish the website with the new aspx page.
Navigate to it's url in a browser, when it opens View-Source.
In the source locate the script src tag.

(start script tag)
src="/UseGalaxyWebControl/WebResource.axd?d=WS6VQ6ceILK4cpcSIBDTOA0gOitJm62vmYH2X7E8EUOB2p55z1WYfEnbnNTg7cQs-HZKaxcnh4sTcOoa0Og_HVTyCk7NIZnZpc-1MUQd7bw1&t=632974654934687088" type="text/javascript">
(end script tag)

Copy the link you find in here. Copy the link back into the browser.
Hit return and you should see the contents of the JScript file you embedded in the assembly.

/UseGalaxyWebControl/WebResource.axd?d=WS6VQ6ceILK4cpcSIBDTOA0gOitJm62vmYH2X7E8EUOB2p55z1WYfEnbnNTg7cQs-HZKaxcnh4sTcOoa0Og_HVTyCk7NIZnZpc-1MUQd7bw1&t=632974654934687088

http://localhost//UseGalaxyWebControl/WebResource.axd?d=WS6VQ6ceILK4cpcSIBDTOA0gOitJm62vmYH2X7E8EUOB2p55z1WYfEnbnNTg7cQs-HZKaxcnh4sTcOoa0Og_HVTyCk7NIZnZpc-1MUQd7bw1&t=632974654934687088
This works because the ASP.NET 2.0 has an assembly reflection type service WebResource.xad. This uses the url passed into the service to extract it from the assembly.
For more see this description
Using the WebResource.axd Handler with Embedded ASP.NET Resources (eggheadcafe.com)


So now you can drag and drop the Custom Control onto your ASPX page in Visual Studio designer. What good is that?
Your aspx page now has access to all your JScript functionality. You can call your JScript functions in the aspx page as normal using the tag.


Resource Caching:
So you've embedded the resource and added it to your aspx.
ASP.NET 2.0 also provides some caching functionality by default.
If the application is in Release (the web.config debug="false" set) all the resources are cached, meaning they will not be reloaded (GET) each time the page is POSTED as long as the resources have not changed.
In debug mode the resources are not cached, so they are always reloaded on page POST.
You'll see in the url for the resource, it contains a t=... this t is the time. This is what's used to compare the cached version of the resource and the latest version on the server.

October 19, 2006

dotNET Custom Configuration Handlers

So you want to add some configurable content to your application/Web application.
The place for your data is in the configuration file, app.config or web.config.
You could put it in the AppSettings, a small problem with this is it uses Key/Value collections which means that the Keys must be unique, that's not the end of the world but you may want to access a complete section in the config file and sort them or something.
The alternative is to create your own section in the config file. To access this you'll need to create your own Handler Class.
I'll explain the settings in the config file followed by the Handler Class and then how to access it.

Custom Configuration Handlers on ASP.NET Forum

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