|
|
Experiences with Microsoft technologies
-
I have spent some time investigating an issue relating to the configuration of WCF web services for SCT as described in this article and specific service accounts. It turns out that when your web service is setup like this and you assign a specific service account rather than use the network service account or the new Application Pool Identities, you may get errors such as “The token provider cannot get tokens for target” or “Secure channel cannot be opened because security negotiation with the remote endpoint has failed. This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint” or “The request for security token has invalid or malformed elements”. These errors are somewhat misleading as to the underlying cause. Instead of having anything to do with security negotiation and tokens per se, I deduced that it appears to be related to the service account not having a user profile on the server. In fact the article above does mention this in the following paragraph, although at first it isn’t an obvious link to the errors highlighted above. “For applications that use stateful SCTs in a secure session, the thread identity for the service must be a user account that has an associated user profile. When the service is run under an account that does not have a user profile, such as Local Service, an exception may be thrown.” Anyway, in order to get around this you can either logon as the service account on the server as part of the deployment (probably not the best option) or change the “Load User Profile” option in the associated Application Pool to True. This will create the user profile for the service account the first time the service is instantiated. You can then change this option back to false if you wish. I would be interested to know exactly what it is from the user profile for the service account that is required when the requireSecurityContextCancellation attribute is set to false, as firstly I would just like to know, and secondly I don’t believe either of the options above are elegant. If anyone can shed any light feel free to let me know.
|
-
I have meant to write a blog post about client certificates in a development environment for a while now, as every time I come to implement it I forget a step somewhere. There are resources online for a number of the steps below, but I wanted to consolidate that information along with my own steps into a single place that I can use as a reference. This may also be useful to others, hence why I am making a blog post rather than file it away in my mesh repository somewhere.
So, what am I trying to do here? Well, I would like to create a WCF service that utilises SSL and requires that clients use a certificate for authentication in a development environment where I do not have any certificates supplied to me. I am setting this up in a Windows 2008 environment (so IIS 7) with .NET 3.5. The whole process will involve the following steps:
- Create certificate to act as a root certificate authority
- Install root certificate
- Install service certificate on server
- Configure site to use SSL certificate
- Export client certificate
- Import certificate on client
- Configure WCF Service
- Configure client(s)
Step 1 – Create Certificate to act as Root Certificate Authority
To use chain trust validation during development you need to create a self-signed root CA and place it in the Trusted Root Certification Authority store. The certificate used by WCF is then created and signed by the root self-signed certificate and installed in the LocalMachine store.
- Open the Visual Studio command prompt and browse to the location where you want to save the certificate files.
- Enter the following command:
Makecert –n “CN=MyRootCA” –r –sv MyRootCA.pvk mYRootCA.cer
- In the Create Private Key Password dialog box, enter a password, confirm the password, and then click OK
- In the Enter Private Key Password dialog box, enter the password again and then click OK.

- You should now have two files MyRootCA.cer and MyRootCA.pvk
Step 2 – Install Root Certificate Authority
The certificate that will be created using this certificate authority will need to have the CA installed on both the client and the server, as it will be used to verify the certificate.
- Follow these steps on both the server and client(s)
- Run MMC
- Add certificates snap-in
- Choose computer account, as this certificate needs to be made available for all users
- Choose local computer
- Browse certificates snap-in and go to certificates node under trusted root certification authorities
- Right-click this and select import from the popup menu
- Browse to the folder where you created the root CA certificate
- Accept defaults for rest of import wizard
- You can double-click the certificate entry to view and validate it installed correctly
Step 3 – Install Service Certificate on Server
You now want to create the certificate for the service on the server and the following steps will do this. Once completed you will see the certificate via the certificates snap-in of MMC and browsing to the following location: Certificates (Local Computer) –> Personal –> Certificates
- Open the Visual Studio command prompt and browse to the location where you saved the Root CA certificate files
- Run the following command
makecert -sk <KeyName> -iv MyRootCA.pvk -n "CN=<MachineName>" -ic MyRootCA.cer -sr localmachine -ss my -sky exchange –pe
- Where <KeyName> is the subject’s key container name (which should be unique) and <MachineName> is name of the server which must match the DNS or NetBIOS name
- Enter the password you defined previously
Step 4 – Configure Site to use SSL Certificate
We now want to configure the website that is to host the WCF service to use the SSL certificate we just created. This step assumes you have already created a website for HTTPS.
- Open IIS Manager
- Browse to “Sites”
- Right-click on your site and select “bindings” from popup menu
- Click edit and from the SSL certificate drop-down choose the certificate you have just installed
Step 5 – Export Client Certificate
Now we want to export the certificate that will be used on the client(s). At the end of this step you should have a new file created with a pfx extension.
- Open MMC
- Add the certificates snap-in and select “Computer Account”
- Browse to Certificates (Local Computer) –> Personal –> Certificates
- Right-click on the certificate you created (should be name of server), select “all tasks” and then “export”
- In the wizard select that you want to export the private key
- From the next screen select the defaults
- Enter a password to protect the private key
- Select where you want to export the certificate and complete the wizard
Step 6 – Import Certificate on Client
Now we need to import the certificate we just exported onto the client(s). You should have already imported the certificate authority in step 2, but if not make sure you do so at this point. Note that we are using the current user here, it just happens to be the way we have things configured later on. You may have a different setup here.
- In MMC, add certificate snap-in for “current user”
- Browse to Certificates (Current User) –> Personal –> Certificates
- Right click this node and select All Tasks and Import from the popup menu
- Follow the steps in the wizard, selecting the pfx file you exported in the previous step
Step 7 – Configure WCF Service
This is the WCF service that we are hosting and requiring authentication for. We happen to be using basicHttpBinding here, but it could be something else
- Make the following entries in your web.config
<services> <service behaviorConfiguration="MyBehaviour" name="MyService"> <endpoint name="MyEndPoint" address="" binding="basicHttpBinding" bindingConfiguration="ClientCertificateTransportSecurity" contract="MyContract" /> <!--<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />--> </service> </services> <behaviors> <serviceBehaviors> <behavior name="MyBehaviour"> <serviceMetadata httpsGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> <bindings> <basicHttpBinding> <binding name="ClientCertificateTransportSecurity"> <security mode="Transport"> <transport clientCredentialType="Certificate" /> </security> </binding> </basicHttpBinding> </bindings>
- Note that if you do not have the mex commented out like above you will receive the error “The SSL settings for the service 'None' does not match those of the IIS 'Ssl, SslNegotiateCert, SslRequireCert, SslMapCert'”.
Step 8 – Configure Client(s)
If using custom app
Make sure you have the following in your configuration file.
<system.serviceModel> <client> <endpoint address="https://myServer/myService.svc" binding="basicHttpBinding" bindingConfiguration="ClientCertificateTransportSecurity" contract="MyContract" name="MyEndPoint" behaviorConfiguration="ClientCertificateCredential" />
</client>
<bindings> <basicHttpBinding> <binding name=" ClientCertificateTransportSecurity"> <security mode="Transport"> <transport clientCredentialType="Certificate" /> </security> </binding> </basicHttpBinding> </bindings>
<behaviors> <endpointBehaviors> <behavior name="ClientCertificateCredential"> <clientCredentials> <clientCertificate findValue="myThumbprint" storeLocation="CurrentUser" x509FindType="FindByThumbprint" /> </clientCredentials> </behavior> </endpointBehaviors> </behaviors>
</system.serviceModel>
Where myThumbprint is available from the certificate
If using a browser to view the service
Internet Explorer
Should just work, a popup should appear that asks you to specify the certificate to pass
FireFox
- You will get an error that says “HTTP Error 403.7 – Forbidden” “The page you are attempting to access requires your browser to have a Secure Sockets Layer (SSL) client certificate that the Web server recognizes.”
- In FireFox go to Tools –> Options –> Advanced –> Encryption –> View Certificates
- Click import and select the certificate with private key file you exported earlier (the .pfx file)
- You will need to clear history now or restart browser
Fiddler
You may want to use fiddler to examine what is going on. When you have fiddler open you will receive a message saying “The server [your server] requires a client certificate. Please save a client certificate in the following location”. Pretty self explanatory. You will need to export your certificate from MMC certificates snap-in, certificates –> personal –> certificates but this time do not export the private key, just export as a DER encoded certificate, copy and rename to the folder/name that fiddler wanted you to.
Issues
“There was an error downloading 'https://MachineName/servicefolder/Service.svc'. The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel”
- If CA not installed on client then a trust relationship cannot be established and the above error can occur
“The SSL settings for the service 'None' does not match those of the IIS 'Ssl, SslNegotiateCert, SslRequireCert, SslMapCert'”
- You will get this error if you do not make sure the clientCredentialType is not set to certificate in the service configuration
- If the mex is not commented out in the configuration of the service
- If the binding of the website isn’t set properly (as shown in step 4)
|
-
So, I haven’t really been doing much with BizTalk for a while now, spending more time on traditional development activities and working on some WCF specific solutions. However, I have recently been investigating SOA implementations in more detail, in particular the ESB (Enterprise Service Bus) along with how and why you would want one of these in your organisation. This has led me neatly back into the BizTalk space. I had actively perused opportunities away from BizTalk, not necessarily due to the fact that I didn’t like working with the product, but more for the desire to get back into pure development like I used to. Hey, it’s nice to have a change every now and again. Now this particular task I am undertaking at the moment is purely focused on Microsoft technologies; I know there are numerous ESB offerings out there from various vendors. So this has led me to the BizTalk 2009 ESB Toolkit 2.0 from a product perspective and looking into some of the enabling future technologies such as WCF/WF 4.0 and the Microsoft Application Server Extensions codenamed “Dublin”. Well, without going into the details of an ESB as there is a wealth of conflicting information out there already, I decided that simply reading about BizTalk 2009 ESB Toolkit would not be sufficient so with a little trepidation I decided to install BizTalk 2009 and the ESB Toolkit onto a VM for testing. I say with trepidation, as I have spent a huge amount of time in the past installing, configuring and generally thumping my head against a heavy object in frustration at the difficulties of getting BizTalk working as expected. However, being a local development install and therefore not having the security locked down that is often the biggest inhibitor to an easy deployment, I was somewhat more optimistic. Anyway, before I decided to plough away at the install I thought it would be prudent to check whether anyone has had experienced difficulties and/or provided some steps to get going quickly; I didn’t want to spend too much time on this activity. So it was with gratitude that I came across this great post by Preetham Reddy. By following these steps I was up and running pretty pain free. I say “pretty” pain free, as I did have one issue that I thought I would make a note of here in case anyone else comes across the same problem. Now, during the configuration steps there is a part where you need to run ESBConfigurationTool.exe to configure the settings for exception management, the ESB core components and configuration nodes. While trying to apply the configuration to any of the databases I would receive an error relating to not being able to create the database. I was logged in as an administrator and I thought this odd, so decided to simply create the databases via SQL Server Management Studio. I ran the configuration again and everything seemed to work fine. I completed the rest of the installation and when i went to browse the ESB Management Console I was presented with the following error: “An unhandled exception has occurred”. “Great” I thought, here we go again, difficulties getting things installed and configured with BizTalk. Looking at the Windows Event Viewer I saw the following entries: Event code: 3005 Event message: An unhandled exception has occurred. Event time: 15/10/2009 18:35:20 Event time (UTC): 15/10/2009 17:35:20 Event ID: 77d00134a17e42519d7c6a11e26ce9d2 Event sequence: 13 Event occurrence: 4 Event detail code: 0 Application information: Application domain: /LM/W3SVC/1/ROOT/ESB.Portal-1-129001012513866430 Trust level: Full Application Virtual Path: /ESB.Portal Application Path: C:\Program Files\Microsoft BizTalk ESB Toolkit 2.0\ESBSource\Source\Samples\Management Portal\ESB.Portal\ Machine name: MyMachine Process information: Process ID: 4584 Process name: w3wp.exe Account name: MyMachine\Administrator Exception information: Exception type: WebException Exception message: The remote server returned an error: (400) Bad Request. Request information: Request URL: http://localhost/ESB.Portal/Default.aspx Request path: /ESB.Portal/Default.aspx User host address: ::1 User: MyMachine\Administrator Is authenticated: True Authentication Type: NTLM Thread account name: MyMachine\Administrator Thread information: Thread ID: 12 Thread account name: MyMachine\Administrator Is impersonating: False Stack trace: at System.Net.HttpWebRequest.GetResponse() at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) Nothing particularly useful there I thought. So I eventually ended up attaching a debugger to the web application and noticed the code was having trouble retrieving data. This is when I remembered the oddity from the configuration so checked the database to see there were no tables, views, stored procedures or anything within them. So I ran through the configuration with ESBConfigurationTool.exe again, but still nothing. I then deleted the databases it had created to see if it would actually create them this time, which it did. I then went back to the ESB Management Console site and viola, there it was. So, I am a little confused why the tool could not create the database the first time, but did the second time. Anyway, this may be useful to someone out there. My thoughts on the whole install and configure process so far is that it is too laborious and error prone, as I half-expected. I want to be able to do one-click deployment, is that too much to ask these days? Perhaps this is the remnants of it being developed externally from the product, but nevertheless it isn’t a great experience for those considering using this on an enterprise-scale project is it? Anyway, back to my investigations…
|
-
I was having a frustrating time zipping files in a Powershell script, one that I had created based on those discussed in David Aiken’s blog post. The name of the zip files created were quite long and were being generated a 8.3 filename automatically whenever the CopyHere method was being called on the zip folder where the files were being added. It was certainly something related to this method, as the New-Zip function was creating the zip file with the desired name, but was renamed only after the CopyHere method was used.
Now I still haven’t found a solution to this problem so if anyone has any suggestions they are most welcome to post them. What I did do however was create a workaround which entails creating the zip file locally on the machine where the script is executing and then move this to the destination. It turns out this problem only happens when attempting to write to a network folder directly.
The following function had the issue with CopyHere
function Add-Zip { param([string]$zipfilename)
if(-not (test-path($zipfilename))) { set-content $zipfilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18)) (dir $zipfilename).IsReadOnly = $false }
# Return the application object $shellApplication = new-object -com shell.application # Returns a folder object for the specified folder $zipPackage = $shellApplication.NameSpace($zipfilename)
# Returns file object for the zip file $zip = Get-Item $zipfilename $activity = 'Zipping file to ' + $zip.Name + ': ' foreach($file in $Input) { Write-Progress -activity $activity -status $file.Name $zipPackage.CopyHere($file.FullName,256) Start-sleep -milliseconds 500 } }
So I simply created a temporary zip and then moved it
# For some reason the filename is getting trimmed when writing directly to the network, so # we use a temporary folder here for storage before moving to the final destination $filename = "$element-$(Get-Date -f dd-MMM-yy-HH-mm-ss)" $zipPath = "$tempFolder\$filename.zip" # Create a new zip file New-Zip $zipPath $path = $element.PSPath
# Add each item in this elements path to the zip file Get-Item $element.PSPath | Add-Zip $zipPath # Now move it to the final destination Move-Item $zipPath $componentfolder
|
-
I have been using ANTS Profiler to conduct some profiling against some WCF services hosted on Windows 2008 that I have been working on. This was working pretty well with services hosted in IIS, but I was experiencing some difficulties when attempting to hook it all up with WCF services hosted in WAS using the net.tcp binding. I still don’t have a definitive answer as to why I have been experiencing issues, but I have a workaround procedure in order to get it working.
Firstly, you need to create a profile and choose the Windows service application type to profile, selected WAS from the, as shown in the following screen capture.

Once you click the Start Profiling button the WAS service should be stopped and started. It is at this point where I experience my first problem, as it seems to hang at the starting state. Note the status bar in the following screen capture.

Now it appears that the service never starts and this state is also shown when you browse the Windows Process Activation Service service in the Services snap-in. After a bit of playing around I managed to get past this issue, by following these simple steps:
1. Execute iisreset from a command prompt window
2. Once iisreset has restarted, browse to an HTTP WCF endpoint on the server
3. The profiler should now be started
Now, at this point I also experienced an issue when attempting to take a memory snapshot, receiving the following error message where <some folder> is the location where it is trying to save the data.
Could not start profiling as the processing being profiled was unable to create the file '<some folder>'.You can set the RGTEMP or the RGIISTEMP environment variables in the System control panel to override the location used for profiler results files.
In order to get around this I simply gave everyone permissions to the folder it was trying to save to. I am sure there was a more focused way that this could be achieved, but as this was a development machine I was quite happy with this.
|
-
I have been working on a WCF intermediary that receives messages from a 3rd party and routes this onto another WCF service. The intermediary service uses basicHttpBinding whereas the destination service is netTcpBinding. I have worked on similar patterns before, but they always had the same binding on each service and they worked well, therefore I hadn’t anticipated any problems.
However, once I had this all set-up I started receiving the following error on the intermediary service: “Addressing Version 'AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)' does not support adding WS-Addressing headers.”
This error appears to stem from the fact that basicHttpBinding is using SOAP 1.1 for the message version and no WS-Addressing, whereas netTcpBinding is using SOAP 1.2 for the message version with WS-Addressing. I had originally attempted to use custom bindings to get over this hurdle without much success so adopted to implement a message conversion in the intermediary service instead.
Your typical intermediary service would tend to have a service contract that is defined as so:
[ServiceContract]
public interface IMyIntermediaryService
{
[OperationContract(
IsOneWay = false,
IsInitiating = true,
IsTerminating = false,
Action = "*",
ReplyAction = "*")]
[FaultContract(
typeof(MyCustomFault),
Namespace = "http://mydomain.com/myapplication/2009/08")]
Message ProcessMessage(Message message);
}
The implementation of the ProcessMessage method would be something like the following. Note that this is a very basic example to be succinct, you would need to include error handling etc. In addition we are defining the destination endpoint in the web.config using the name “destination” as the identifier.
public Message ProcessMessage(Message message)
{
var channelFactory = new ChannelFactory<IMyIntermediaryService>("destination");
IMyIntermediaryService forwardingChannel = channelFactory.CreateChannel();
Message responseMessage = forwardingChannel.ProcessMessage(message);
channelFactory.Close();
return responseMessage;
}
Now, in order to handle the message conversion you would supplement the above code so that it identifies the message version received. Note that we are solely checking for netTcpBinding here, but this code could be modified to expand upon this to make it more generic.
public Message ProcessMessage(Message message)
{
// Get the message version
MessageVersion returnMessageVersion = message.Version;
bool messageConverted = false;
var channelFactory = new ChannelFactory<IMyIntermediaryService>("destination");
IMyIntermediaryService forwardingChannel = channelFactory.CreateChannel();
// If we are using NetTcpBinding make sure that the message we are sending is
// Soap 1.2 WS-Addressing if it is not already
if (channelFactory.Endpoint.Binding.GetType() == typeof(NetTcpBinding)
&& message.Version != MessageVersion.Soap12WSAddressing10)
{
message = CreateMessageCopy(message, MessageVersion.Soap12WSAddressing10);
messageConverted = true;
}
Message responseMessage = forwardingChannel.ProcessMessage(message);
channelFactory.Close();
// Convert the message type back to that of the original if necessary
if (messageConverted)
{
responseMessage = CreateMessageCopy(responseMessage, returnMessageVersion);
}
return responseMessage;
}
Note that you must also covert the result back to the original format if a conversion has taken place otherwise the client will throw an exception “An error occurred while receiving the HTTP response to http://myserver/myservice.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.”
The conversion method would be something like the following
private static Message CreateMessageCopy(
Message message,
MessageVersion newMessageVersion)
{
Message copy = Message.CreateMessage(
newMessageVersion,
message.Headers.Action,
message.GetReaderAtBodyContents());
copy.Properties.CopyProperties(message.Properties);
return copy;
}
|
-
I had been working quite happily with Castle Windsor and WCF services using WCF Facility when implemented through an HTTP binding of some description. You simply hook in the DefaultServiceHostFactory from Castle.Facilities.WcfIntegration into your ServiceHost declaration such as the following example:
<%@ ServiceHost Language="C#" Debug="true" Service="MyService" CodeBehind="MyService.svc.cs"
Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" %>
You would then register the WindsorContainer within the Application_Start event of your Global.asax like so or however you prefer register your components, the point being it is done in the Application_Start event.
protected void Application_Start(object sender, EventArgs e)
{
var container = new WindsorContainer("ioc.config");
DefaultServiceHostFactory.RegisterContainer(container.Kernel);
}
However, let’s say you are binding to net.tcp and hosting in WAS (Windows Process Activation Service)? This event will not get called, so you need to find another way to initialise your Castle Windsor container.
I confess I spent a while looking at the Host Factory in more detail, looking to wrap the DefaultServiceHostFactory. However, there appears to be a far simpler solution and that is to make use of the little documented AppInitialize method. If you create a class (any class), put it into the ASP.NET App_Code folder in your project and give it a method signature as defined below, this little baby will get fired exactly when you want it to. You can then initialise your IoC container in there.
public class InitialiseService
{
/// <summary>
/// Application initialisation method where we register our IOC container.
/// </summary>
public static void AppInitialize()
{
var container = new WindsorContainer("ioc.config");
DefaultServiceHostFactory.RegisterContainer(container.Kernel);
} }
|
-
This post is more a reference to me in case I come across this again, but also to anyone else that may experience the same error, as I couldn’t find any reference to it when searching online.
It was one of those infuriating situations where you believe everything is set-up how you expect, but you keep receiving an unexpected error. Therefore you know something isn’t quite right somewhere along the line and most likely something simple. So, after spending a bit of time going through the debug motions you obtain the extra eyes of a few colleagues to verify your sanity. Alas, still no joy. Then, after more frustration it suddenly springs out at you and you groan with the simplicity of it.
Anyway, in my case I was attempting to use Castle and WCF. We had this working fine on various projects using the WcfIntegrationFacility, but for some reason on this new set-up we were experiencing the error: “Could not find a component with the name <my component name>, did you forget to register it?”
It turns out that the id on the component element in the Castle configuration must exactly match the class type. For example in the configuration snippet below, the two highlighted must be the same otherwise you get the error described.
<components>
<component id="This.Should.Match"
service="Some.Interface, Some.Assembly"
type="This.Should.Match, Some.Assembly">
</component>
</components>
I won’t be forgetting that one in a hurry.
|
-
After following through various step-by-step instructions on getting the JQuery intellisense to work with Visual Studio 2008 SP1, I was still having issues getting it to work correctly. The first and slightly more obvious reason for the intellisense to not work was down to using absolute paths for the script file.
<script type="text/javascript" src="/Scripts/jquery-1.3.2.min.js"></script>
This should be
<script type="text/javascript" src="~/Scripts/jquery-1.3.2.min.js"></script>
The second and far more idiosyncratic problem was occurring when I had also referenced other script files. So, I would have something like the following.
<script type="text/javascript" src="~/Scripts/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="~/Scripts/another-script.js"></script>
Strangely enough every time I referenced an additional script to the jquery core in my Site.Master the intellisense would suddenly stop working. It turns out that there is a dependency on an associated file named with a –vsdoc suffix to the script filename.
For the above example you would need an “another-script-vsdoc.js” file located in the same folder as the actual script file. It doesn’t matter whether this contains any comments to support Visual Studio intellisense, it merely needs to exist.
An additional note to point out is that the intellisense will not work if you are using any kind of server side scripting in the path, which is also pretty obvious if you think about it.
<script type="text/javascript" src="<%=ResolveUrl("~/Scripts/jquery-1.3.2.min.js")%>"></script>
|
-
I have been working with ASP.NET MVC over the last few days and wanted to implement dependency injection utilising Castle Windsor. I spent a while nosing around the web for some articles on this and although I found a few there wasn’t anything definitive. So once I had a working version of this on my development VM I thought I would write this post to record my findings.
Firstly, we need to hook into the Application_Start within Global.asax. In here we want to use the ControllerBuilder SetControllerFactory method to specify our own ControllerFactory that will encapsulate our Inversion of Control container of choice, in our case Castle Windsor.
/// <summary>
/// Application on start.
/// </summary>
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));
}
Our custom ControllerFactory class is then defined like so
public class ControllerFactory : IControllerFactory
{
private readonly WindsorContainer container = new WindsorContainer(HttpContext.Current.Server.MapPath("~/Windsor.config"));
public IController CreateController(RequestContext requestContext, string controllerName)
{
return (IController)container.Resolve(controllerName);
}
public void ReleaseController(IController controller)
{
container.Release(controller);
}
}
We have implemented our own version of the CreateController and ReleaseController methods. In the CreateController method we use the WindsorContainer to obtain the class to be used. This piece of logic is achieved through Convention over Configuration, with the controller name specified being the name of the controller without the Controller suffix. So for example the HomeController class would have the name “Home” and the AccountController class would have the name “Account”.
We then also explicitly release the controller in Castle Windsor to make sure there are no leaks.
The config below gives and example of the windsor config
<configuration>
<components>
<component
id="Account"
type="MVCDemo.Controllers.AccountController, MVCDemo"
lifestyle="transient"/>
<component
id="Home"
type=" MVCDemo.Controllers.HomeController, MVCDemo"
lifestyle="transient">
<parameters>
<TestGateway>${testGateway}</TestGateway>
</parameters>
</component>
<component
id="testGateway"
service=" MVCDemo.Gateways.IGateway, MVCDemo"
type=" MVCDemo.Gateways.TestGateway, MVCDemo"
lifestyle="transient">
</component>
</components>
</configuration>
In the configuration above we are defining two Controllers; the HomeController and the AccountController using the identifiers mentioned previously. These specify the concrete classes to be used.
Additionally, we are specifying that the HomeController has a dependency on the TestGateway class, which implements the IGateway interface. This is all purely for example, but this dependency could be switched easily at a later date to another class that implements the IGateway interface by simply updating this configuration file. I won’t show the definition for the TestGateway class or IGateway interface, as it is irrelevant for this example.
Finally, a modification is required to the HomeController so that the constructor accepts the dependency we have identified.
public HomeController(IGateway gateway)
Now, spinning up the application means the Account and Home controllers being used are those specified in our Windsor configuration file and we are also passing in the TestGateway to the Home controller. On top of this, we can also test the HomeController more effectively by mocking out the IGateway interface using something like Rhino Mocks.
|
-
This is really a note to self, as I have a habit of forgetting the numerous issues I have overcome and feel my blog can be a great repository for such information, as it may also assist someone else out there. I haven't been as rigorous with this as I should have recently. Well, for a long time actually! Anyway, quite a simple one really, but one I have managed to forget. If you are setting up a new WCF web service hosted within IIS you may receive errors such as that below: Event Type: Error Event Source: ASP.NET 2.0.50727.0 Event Category: None Event ID: 1088 Description: Failed to execute request because the App-Domain could not be created. Error: 0x80070005 Access is denied. Event Type: Warning Event Source: ASP.NET 2.0.50727.0 Event Category: None Event ID: 1073 Description: Failed to initialize the AppDomain:/LM/W3SVC/1/Root/<your app domain> Exception: System.IO.FileLoadException Message: Could not load file or assembly 'System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. Access is denied. StackTrace: at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) at System.Activator.CreateInstance(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo, StackCrawlMark& stackMark) at System.Activator.CreateInstance(String assemblyName, String typeName) at System.AppDomain.CreateInstance(String assemblyName, String typeName) at System.AppDomain.CreateInstance(String assemblyName, String typeName) at System.Web.Hosting.ApplicationManager.CreateAppDomainWithHostingEnvironment(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters) at System.Web.Hosting.ApplicationManager.CreateAppDomainWithHostingEnvironmentAndReportErrors(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters I am sure there are other reasons for receiving these errors, but the times I have come across it have been due to the account defined withint the associated application pool not having read permission to the application's web.config file.
|
-
A large percentage of issues in the numerous BizTalk 2004 environments I have encountered with at my current client have been related to configuration. The current build of the environments are conducted in a semi automated fashion; the initial build is performed by Altiris and then there are a number of steps carried out either manually or through automation scripts thereafter. This is obviously far from ideal, as any manual configuration is prone to errors. The favoured solution would be to script the build of the entire environment and then provide a simple button for some operational employee to click that would go off and build the whole thing for you. There are products out there that can achieve this for you, an example being Microsoft’s APF (Automated Purposing Framework) that they apparently use to do just that internally. However, your client may not be in a position to implement an external product to conduct any automation of builds for various reasons, so you would be stuck in a similar predicament whereby the build is a mishmash of manual and automated steps. To complicate matters further, the environment at my current client is built to be a shared service. A standard integration platform based on BizTalk 2004 is deployed in the numerous environments (dev, system test, pre-production and production) and then applications are installed on top of this platform. The complexity here is that each of those applications may also have some environment configuration requirements and in one particular case we have a large, business critical application that makes numerous changes to this generic platform. That is enough of the background information. The point to this narrative is that managing configuration of integration platform environments can be quite complex. Tools to consider when attempting mitigating the risks involved include automated build tools as mentioned above, but also configuration management tools such as the product that I have been pushed to evaluate for this purpose at my current client – Microsoft DCM (Desired Configuration Monitoring). Now I will hold my hands up here. Until recently Configuration Management had been a concept for others to contend with. In my professional career I have been primarily involved with development until getting involved with BizTalk since the 2004 version. Therefore my exposure to technologies such as SMS (Systems Management Server), MOM (Microsoft Operations Manager) and the like had also been limited. During the last few years I have found MOM to be a very useful solution and due to necessity I am now finding SMS and DCM to also be equally useful when attempting to solve the numerous challenges involved when managing an Integration Services platform. My initial focus has been on evaluating DCM and was the main reason for this post. This evaluation has simply entailed investigating the potential use by focusing on the manifests used by the DCM tool to report upon a server’s configuration. In case you have not come across DCM before, manifests are simply XML files that define a number of rules according to the DCM schema that are then used by the tool to report on any differences found on a specified server. So for example, you may wish to create a rule that ascertains whether the HTTP Batch size on your BizTalk 2004 HTTP Send Host server is set to 1. Perhaps this setting is essential for the applications hosted on that environment to function as expected. In this case you would use the freely supplied Authoring Tool to enter the configuration rule, save the manifest and then execute DCM, passing in this manifest to use. As a quick note, for our investigation we are conducting this manually through the executable directly rather than utilising SMS where the functionality can be automated. Anyway, I have been using this tool for a number of days and have to say in some frustration. I understand that this whole solution is freely available from Microsoft so you should not expect too much, but the whole authoring process seems unnecessarily complex and convoluted. The XML schema in particular seems to be illogical and the authoring tool hampers progress as much as aids it. This may lead the cynic in some people to think this was done on purpose so that Microsoft could sell their consulting services to produce ready built manifests and/or assist in the creation of those that are not already available. However, once you have defined your manifest(s) the tool is certainly a useful addition to your armoury when dealing with the issues described earlier. Due to the amount of configuration applied to our environments I was never entirely convinced that they had been configured as per the instructions. Even the automated steps could potentially have incorrect parameters passed to them due to process. So being able to use DCM to check the most obvious configurations were applied correctly certainly assisted in providing a higher level of confidence. So for me, this freely available utility has given me an immediate benefit even when a reasonable amount of investment time up front when authoring the manifests has to be factored in. This has been gained simply by executing the tool manually, the next step will be to look at the automation of this through SMS and the generation of reports based upon the results. However, we may not be taking this particular route just yet. We may decide to stay with the simple manual execution for the meantime and look at establishing Microsoft Systems Center at the client, which introduces Microsoft System Center Configuration Manager 2007 – the successor to DCM. I have had a relatively brief presentation of this product by Microsoft and have to say I was quite impressed. It seems to encapsulate MOM, SMS and DCM within a more integrated solution while providing much needed enhancements to those individual products. If you have any vested interest in making sure your environments are managed affectively and have any investments in those products, if you have not already spent some time investigating Microsoft System Center I would strongly suggest you do.
|
-
Firstly, I knew it had been a long time since I posted on my blog, as I have been snowed under with work for my current client and none of this work warranted any posts on the subject. However, I must admit I didn’t realise how long ago it was since I actually posted. Doesn’t time fly huh? I can’t say I know where this year has gone, but we all say that every year don’t we? Anyway, I solved a relatively simple (but annoying) problem today that I hadn’t encountered before that didn’t have much information available on the internet; well, not for my particular scenario. So I thought it would be worth popping on my blog, firstly as a simple wave to say I am still alive and secondly as a reference for me in the future. You know how it is, you spend time solving problems then encounter them a few months later only to forget how you solved it. Well, I feel the blog is a good repository for this kind of information. So, what was the issue? Well, one of our testing environments had taken a bit of a pounding recently with various non-functional tests. This is never healthy if you wish to come out at the end with the exact same environment as you started without some form of rebuild be it automated or not. While trying to deploy a custom adapter to this environment numerous errors were occurring, which led to the conclusion that there was in issue with SSO. A highly likely conclusion considering one of the non-functional tests included the restoration and movement of SSO. During the investigation it was observed that whenever you tried to register a new adapter you would receive the following error: SSO AUDIT Function: CreateApplication Tracking ID: e902339c-b431-40e5-a880-337bb873725b Client Computer: <Computer Name> (wmiprvse.exe:1232) Client User: <User Name> Application Name: {11C54F41-4C5A-4929-B828-7CD6E550BEB8} Error Code: 0xC0002A18, The format of the account name is not valid. Domain accounts must include the domain name. Local accounts must not include a domain or computer name. This naturally led to an examination of all things related to SSO, in particular the SSO services. You would have thought from the error message that the service account used for SSO was incorrect. However, after too much time it transpired that the default BizTalk Host was registered using an incorrect domain group; it actually wasn’t in the domain as per the above error. And the conclusion to this little story? Spend a little more time studying the GUIDs in the error. Only in hindsight did I think about searching out the details to find they would have guided me to the answer more quickly.
|
-
I have had to park my work on BizTalk 2006 while I assist another team at my current client on some BizTalk 2004 work. I was helping to install and configure some BizTalk groups and remembered just how much of a pain this can be and how much this has evolved in BizTalk 2006.
Anyway, I had an issue during the pre-installation of Visual Studio 2003 on a Windows 2003 SP1 server that took me some time to fathom out. Checking the error log highlighted the following errors in particular:
[03/13/06,10:57:24] Microsoft FrontPage 2000 Web Extensions Client: ***ERRORLOG EVENT*** : Error code 1603 for this component means "Fatal error during installation.
[03/13/06,10:57:24] Microsoft FrontPage 2000 Web Extensions Client: ***ERRORLOG EVENT*** : Setup Failed on component Microsoft FrontPage 2000 Web Extensions Client
[03/13/06,10:57:27] Setup Runtime Files: ***ERRORLOG EVENT*** : Error code 1603 for this component means "Fatal error during installation.
[03/13/06,10:57:27] Setup Runtime Files: ***ERRORLOG EVENT*** : Setup Failed on component Setup Runtime Files
[03/13/06,10:57:30] Microsoft Visual J# .NET Redistributable Package 1.1: ***ERRORLOG EVENT*** : Error code 1603 for this component means "Fatal error during installation.
[03/13/06,10:57:30] Microsoft Visual J# .NET Redistributable Package 1.1: ***ERRORLOG EVENT*** : Setup Failed on component Microsoft Visual J# .NET Redistributable Package 1.1
[03/13/06,10:57:32] setup.exe: ***ERRORLOG EVENT*** : Unable to open g_szRegkeyMSIntegration in CSetupManager::RemoveSetupFiles()
[03/13/06,10:57:32] setup.exe: ***ERRORLOG EVENT*** : CSetupManager::RemoveSetupFiles() failed in CSetupManager::RunInstall()
[03/13/06,10:57:32] VS70BaseUI: ***ERRORLOG EVENT*** : DepCheck indicates Microsoft FrontPage 2000 Web Extensions Client is not installed.
[03/13/06,10:57:32] VS70BaseUI: ***ERRORLOG EVENT*** : DepCheck indicates Setup Runtime Files is not installed.
[03/13/06,10:57:32] VS70BaseUI: ***ERRORLOG EVENT*** : DepCheck indicates Microsoft Visual J# .NET Redistributable Package 1.1 is not installed.
After some considerable amount of time researching what could be the root cause, I stumbled across the following KB article that led me to the answer http://support.microsoft.com/default.aspx?scid=kb;en-us;327763
In my scenario the servers that I received had an incorrect mapping for the “My Documents” folder, which pointed to a network folder that did not exist. I changed this to point to a temporary folder located on the local machine and the installation continued successfully.
I hope this post may help save someone else time.
|
-
At my current client they have been relatively slow on the uptake of Windows Server 2003 SP1, so those of us working within the Integration Services team have not had to deal with any complications that this service pack has introduced to BizTalk. Recently however we have been installing SP1 and have noticed a number of errors that have been introduced because of this.
We observed that BizTalk Host Instances were being stopped and restarted automatically. Following this up in the Windows Event Log we noticed a number of error messages relating to DBNETLIB and other entries indicating that there were issues relating to network connectivity. Some captures of these are shown below.


After some research we came across the following Knowledge Base article at Microsoft: http://support.microsoft.com/default.aspx?scid=kb;en-us;899599
Now the symptoms described in this article are exactly what we were experiencing. Apparently Windows SP1 introduces some extra security feature that reduces the size of the queue for concurrent TCP/IP connections to the server, which helps to prevent denial of service attacks.
All well and good, however the article suggests the actual issue only materialises when TCP/IP is under heavy load, sometimes incorrectly identifying valid TCP/IP connections as a denial of service attack. However, we have been receiving the errors when the BizTalk Group was under no load whatsoever.
After implementing the registry modifications in that article the problems did disappear, but I am interested why the BizTalk Group was experiencing the condition at all when there was no load. I spent some time investigating what may be the root cause and the only conclusion I could come to was that it may be related to the number of host instances that we had within the BizTalk Group; there were 40 in this case.
I have not had the time to investigate this any further, although a simple enough test would be to see whether the errors materialise with less host instances. One other thing that I did notice after installing Windows 2003 SP1 though was the number of security log entries. Is it just me or do we now see a huge increase in the number of entries? Something else I would like to investigate time permitting.
Just a final note, I have seen this occur with both BizTalk 2004 and BizTalk 2006.
|
|
|
|