iMeta Consultancy Services

Syndication

Blog Stats

  • Blogs - 75
  • Posts - 627
  • Articles - 0
  • Comments - 18563
  • Trackbacks - 3879

Bloggers (posts, last update)

Latest Posts

SSRS 2008 Access Denied on Fresh install

I’ve just spent the last hour trying to get SSRS working from my localhost and could not for the life of me understand why I kept getting the error below when I navigated to http://localhost/reportserver

The permissions granted to user '<domainName>\<username>' are insufficient for performing this operation. (rsAccessDenied)

I had set SSRS up to execute under my domain account, which was also a local admin account, so as far as I could tell I had full permissions on the machine. SQL Server was setup to use the same account and I could access the reporting databases from the SSMS.

If I also navigated to http://localhost/reports I got back a basic page, but with no reports visible.

image

I then tried to deploy my reports from Visual Studio, just for the fun of it, and it worked. However I still got the same error message when I navigated to the localhost. So with some head scratching I suddenly realised that my Visual Studio was running as Administrator (due to the location of the source).

So I reran IE as the Administrator and I could now see my reports.

image

This now meant I could follow the steps on the Microsoft Site to setup my domain user, by clicking on the Properties tab, selecting New Role Assignment, and entered my domain\username. Once I had done this everything worked as expected from a normal IE browser Window.

posted @ 2/24/2011 2:49 AM by Stephen Goodman

Image Panning with jQuery UI

I’ve been working on a small proof-of-concept (aka POC) over the past week or so.  The brief was to mimic deep zoom within a web app on the iPad – there is a JavaScript deep zoom library (http://gallery.expression.microsoft.com/SeadragonAjax) but this performs very slowly on the iPad and was therefore not suitable.  As such the POC uses a series of images at different zoom levels, e.g. five levels of zoom equals five separate images.  The POC allows the user to pan/drag the image around using touch events and to change zoom level using a pinch gesture.

Before venturing onto the iPad and hooking up the touch events and pinch gesture, I wanted to get the image panning/dragging working within a desktop browser environment.  I used the draggable widget from the jQuery UI  library to achieve this.  There is some simple-ish maths involved to make sure that the image cannot be panned/dragged beyond it’s boundaries.  There is a demo over at http://jsbin.com/opehi4/5 - any comments/questions are very welcome.

In the near future I hope to post some details of the jQuery plugin that I developed to capture the pinch gesture on the iPad and mobile Safari in general, until then…

posted @ 2/22/2011 11:21 PM by Mike Godfrey

Chrome Style Tabs with jQuery UI

Due to a fairly heavy project workload, I’ve been a bit quiet on the blogging front recently – this small post on creating Chrome style tabs with the excellent jQuery UI library should rectify that.

First off lets define what I mean by Chrome style tabs – the rightmost tab is used to add a new tab but is not actually selectable, every other tab is based on a template and is selectable and removable.  The template could be anything you want, in my most recent project it was a data entry form to capture the same information for a collection of data items.

I’ve put a demo up over at http://jsbin.com/uyedu4 – enjoy!

posted @ 1/26/2011 1:56 AM by Mike Godfrey

Combining Validation of Transactional and Persisted Data

 

Overview

Our Standing Settlement Instruction (SSI) reference data management solution, Assassin is built upon a generic reference data management framework, where one of its components is a validation framework.

One of the main features of this validation framework is to allow the definition of validation rules based on XPaths that define if data is valid or not. These rules allow complex cross field validation rules to be defined so that standard market validation rules for SSI’s can be represented. In addition defining validation rules using XPath’s allows their addition to and customisation by the Assassin end user via a rule editor provided in the Assassin UI.

The validation framework works well for data received in a transactional processing style being invoked when an single reference data object requiring validation is received via a messaging system from an external data provider. The validation cycle can be summarised via through the following steps:

Receive new/updated reference data object (SSI)

  1. Start Validation
  2. Convert object to XML
  3. For each xpath validation rule find invalid fields by running XPath against the XML

 

The performance of the validation cycle is high taking little time compared to the action of actually persisting the data, the use of compiled XPath’s as provided for in the Dot Net runtime significantly helping here.

The downside in validating data this way is that its does not perform particularly well against data already in the database, requiring it to be extracted, converted to XML and the validated. Essentially the validating of data present in the database is just a query performed against the database to find what data is invalid, a query will be much quicker than extracting and transforming the data.

The next three sections details why validation of existing data is a requirement and a solution that works for both transaction and bulk object validation, The last two sections provide a rational detailing why the solution is required and a conclusion providing a more abstracted view of the solution.

 

Bulk Data Load

Assassin allows for the bulk data load of SSI and related information. A bulk data load takes a file containing a large number of SSI’s or other reference data objects and loads them in one go into Assassin.

At present bulk loads are performed by hooking into the transaction processing part of Assassin for each data object being loaded. This limits the bulk data import speed to the 100’s of objects a second but has the benefit that data imported via a bulk import has exactly the same processing steps as for any data entering Assassin including running validation rules.

One of the principle reasons why bulk data is loaded in a transaction style is so that the validation rules are run against the data to find invalid reference data objects. In general there are processes run when invalid data is found, for example creating a task for a user to fix the data, but these could be triggered once the loading of data has completed, only running on the set of data which is invalid.

An alternative would be to bulk load data directly into the database tables used to store the reference data objects (directly being via a ETL mechanism typically using some form of staging table) and then using a database query to find data that is invalid.

 

Adding and Amending Rules

Validation rules can be added to or amended, but rules are only run for new transactions. Therefore data that would be made valid or invalid due to a change to the validation rules is not automatically picked up when the rule is enabled. There are mechanisms in Assassin to queue a background re-validation action against a given reference data object, but this requires the identification of which objects to revalidate. Re-validating all data in the database would take significant amounts of time, and is not a solution when the rate of rule amendment is high.

Finding which reference data objects to revalidate when validation rules are changed is currently performed via custom SQL scripts where there is a requirement for retrospective validation of data.

 

Running XPath rules against the database

The article is about the concept of taking the definition of a validation rules orientated towards transaction orientated processing of a single reference data object and and using the same definition to form an expression to scan the persistent storage of large number of objects.

Assassin has a framework that lends itself to this task; the data structure definition in Assassin is an XML schema file; every reference data type stored on the database has an XML schema type definition. The schema definition underpins many aspects of Assassin but the two of interest to a solution are:

  • The schema defines the XML used when performing the validation.
  • The schema defines an XPath based query mechanism used to query the database.

 

Therefore the framework Assassin is built on lends itself to using the XPath rule definition to query the database. The XPath database query mechanism has implemented a significant proportion of the XPath language, the market based rules Assassin has for validating SSI’s can all be run as database queries via the XPath query mechanism.

 

Rational

Why is important to re-use the XPath definition we have for validating a single reference data object for running a query against the database? An alternative could be to define a SQL query against each validation rule.

One of the most important reasons is that you only need to define the validation rule once. This is very important from a testing perspective as the rule can be tested once using the testing tools provided for in the Assassin UI. A SQL query to find invalid data would require the same development time as the original validation rule and typically greater time to test it picks out the same data as the XPath.

The second significant reasons is that XPath rule definitions can be edited within a UI designed for writing validation rules by an end user skilled in XML and XPath usage which is a common industry standard skill. The user is presented with the XML they are validating against generated from the screens used to edit actually edit the data by the end user. Typically the XPath’s used to define rules are simple and a skilled business analyst can take existing rules as a bases for defining their own custom rules. Creating such an editor to work with a sql query would require significant amounts of effort.

Adding the requirement to also write a SQL query would mean the end user also needs to be skilled in the database data definition used to represent the same data and have SQL skills.

An alternative would be to switch the validation rules to being defined in a database query expression language and perform validation only on persisted data; using an ORM tool for abstraction away from specific database types and the partially from the underlying database schema. There would also be a requirement to match the current behaviour of the Assassin client which runs validation rules client side allowing for the immediate feedback of validation errors to a user entering data.

A rule defined as an XPath written against an XML Schema provides a significant level of abstraction away from how the data is persisted. Apart from abstraction from a particular database type it is typically beneficial to abstract and isolate a business user from the mechanism used to persist the data, having validation rules written in query language forces the end user to have knowledge of how Assassin persists its data.

Using XPath as a common query expression for transaction as well as persisted data is the solution with the most benefits to the Assassin product as it allows validation rules to be run outside the server and to abstract the rules away from the data persistence.

 

Conclusion

The Assassin product has a framework that is heavily based around XML technologies; having a common XML schema for defining reference data types used for performing validation via XPaths and searches via the database via the same XPaths. Improving its validation framework to allow performant retrospective validation via database queries will not require significant effort.

From an data architectural perspective the solution highlights that there are significant gains in using a single mechanism for defining data types and for querying over those data types. An alternative design may have separated out the database type definition from the type definition used to validate data. Such designs will typically prevent a mechanism to query both sets of data using a common query expression as there is no easy way to map between the two type definitions.

Use of an XML schema itself isn’t a requirement to achieve commonality between the data types used in persistent storage and its manipulation in a transactional processing system, various ORM tools perform this function, the downside would be exposing the ORM’s query mechanism to when defining validation rules or defining an expression language that is an abstraction onto that query layer.

Using the range of XML technologies for processing data requiring validation has significant benefits as it provides common well known mechanisms for manipulating transactional and persisted data in a range of scenarios using a common set of rules.

posted @ 11/2/2010 4:41 AM by James Allderidge

Oracle Dot Net Data Provider (ODP.NET) Memory Leak

 

We’ve come access an issue where the Oracle Dot Net Data Providers appear to leak memory under certain usage scenarios. The issue occurs in the latest 11g client releases, tested up to version 11.2.0.1.2.

Essentially we had a process executable, which leaked memory when calling the Oracle drivers when the following connection settings were present:

PROMOTABLE TRANSACTION=LOCAL

These settings disable distributed transaction management of the connection and are made to improve the speed of the application.

We initially found that involving DTC stopped the memory leak, so changing the settings to just ‘enlist=true;’ and removing the promotable transaction settings stopped with leak. This wasn’t an ideal solution as it reduced performance and also occasionally left an in-doubt transaction which required a DBA to resolve.

What we found was that the process used had its main method marked with the [STAThread] attribute, which will alter how the application communicates via COM and therefore the Oracle client drivers, as these are native. Removing the attribute resolved the memory leak problem and we were able to go back to using local non-distributed transactions to Oracle again.

posted @ 9/14/2010 4:28 AM by James Allderidge

The Task Parallel Library Series - The Task Class

Now that we understand the principles of Task Parallelism, let's see how to do it in .Net 4. In previous versions of .Net, there were two main options. One was to launch a new thread for each task:


var thread = new Thread(() =>
	{
		DoSomeWorkHere();
	});

thread.Start();

DoOtherWork();
DoOtherWork();
DoOtherWork();

thread.Join();

Console.WriteLine("All work completed");	

The other was to make use of the built-in thread pool1:


ThreadPool.QueueUserWorkItem(_ =>
	{
		DoSomeWorkHere();
	});

DoOtherWork();
DoOtherWork();
DoOtherWork();

Console.WriteLine("My work completed.");
Console.WriteLine("No idea what the threadpool task is doing.");

Which of these was best? Well, it largely depends on what you are doing. If you have some long-running task2 to execute then launching a new thread is probably a reasonable way forward; although threads are relatively expensive objects, the cost is amortised over the life of the task which, for big tasks, makes the overhead pretty much irrelevant. It also leaves the thread pool (which has a limited number of threads) available for doing what it does best, which is the execution of relatively small tasks.

In general, the thread pool tended to be the option that most people went for; long running tasks are not that common (remember that the longest sequential chain limits how fast your code can ever run, so long running tasks are best avoided), and the thread pool offered a good combination of ease of use and performance.

However, to do anything more than a "fire & forget" approach with the thread pool is problematic. Once you call QueueUserWorkItem, you essential loose contact with the work that you've just submitted. To keep in touch, you need to hand roll the code yourself (usually involving some combination one of more ManualResetEvent or Monitor objects). Why would you need to keep in touch? Well, if the tasks is performing some form of calculation or gathering data from some external service, you'd probably quite like to access the result. Sure, it can stick that in some member field of a class that is shared with the calling code, but you still need to know when the processing is complete before you attempt to access the field. (Hmm, shared stuff again. Wasn't that bad or something?).

Plus, what if your processing throws an exception? You need to handle that, otherwise it's game over for the whole process3. So you need to have a mechanism for communicating these events back to the "main" thread. And how about cancellation? What if a user initiates some task that could take some time, and then changes her mind? Ideally, you'd like to cancel that task to save on the unnecessary processing. Again, here come those volatile flags, events etc. to let you perform such synchronisation.

This is all pretty unsatisfactory. There's an awful lot of plumbing that needs to be written when using either the thread pool or regular threads, and this code obscures the logic that you're trying to express (you know, the stuff the customer is paying for. They typically don't give a damn about all this threading stuff). Plus it tends to end up relatively complex and hard to reason with, which makes the creation and/or introduction of bugs more likely.

So, this post is all about .Net 4 and yet all I've done so far is moan about the previous state of affairs. Let's see some new code:


var task = Task.Factory.StartNew(() =>
	{
		return DoSomeWorkHere();
	});

DoOtherWork();
DoOtherWork();
DoOtherWork();

task.Wait();

Console.WriteLine("All work completed. Task returned {0}", task.Result);

Simple stuff to start with (future posts will expand much further), but this code starts a Task and then proceeds to do some other work. At a later point, it waits on the task and gets back the result. You'll note the total absence of anything to do with threading - no locks, no events, nothing. You'll also note that there's no shared state - the Task does it's work and returns the results - no messing about with shared fields and the associated synchronisation.

So what are the Task and the Factory types? You can think of Task as a representation of some value (the result) which will be available at some point in the future, and it provides suitable members for waiting on and accessing the result once execution completes. The Factory provides the abstraction over the mechanism by which the task is scheduled & executed - is it in the thread pool, does it run on some specific thread (maybe the UI thread, for example) or is it some async call that doesn't actually have a thread permanently associated with it? The default factory (as used above) simply delegates to the thread pool (but with all the plumbing that's needed to make it useful) but that can be overridden, which we'll look at in a future post

So, that hopefully gives you an easy introduction to the Task class. Future posts will drill into more depth on usage scenarios, covering many of the things that were problematic prior to .Net 4.0.


1BTW, what's with that odd "_" in the lambda for QueueUserWorkItem? Well, the delegate that it expecting is a WaitCallback, which is defined as public delegate void WaitCallback(object state);. From that, you can see that any method being used as the start of a thread has a state argument. In our lambda, we don't make use of this, and the convention is to use "_" as the name for an unused argument in a lambda. "_" is a perfectly valid C# identifier, so there's no magic here. Of course, if you have more than one argument that is unused, you can't use "_" for both of them!

2By long running task, I mean some continuous "thread" of execution within a program. Clearly there are many examples of long running business tasks that can lasts many hours (or days or weeks), but this behaviour is typically implemented through some state that is persisted and "resumed" at the appropriate points. Trying to model a business process by running a single thread that starts when the business process starts and just keeps running until the business process has finished is unlikely to be a great solution :)

3By default (and quite correctly, IMO), the .Net runtime will abort any process that has an unhandled exception on any thread. This was a change made in, if I recall, .Net 2.0 - prior to that, it was only unhandled exceptions on the main thread that caused the process to abort. On other threads the thread would just silently die, leaving the application running but now in some (by definition) undefined state. I don't know about you, but hoping that code is going to execute properly when the application state is undefined doesn't sound like the best idea in the world.

posted @ 8/30/2010 1:31 PM by Steve Strong

JQuery and OData

A common model enabling a web application to search a remote source for data could be as follows.

The HTTP POST method allows the data set of an HTML form to be sent to a processing agent, typically a web server.  The web server is responsible for querying a remote data source, typically a database.  This can be achieved using a variety of techniques, such as old-fashioned ADO.Net in the ASP.Net page code behind or by more up-to-date ORM technologies.  The web server will use the result of the data source query to re-render the HTML page and send it back to the browser.

There are several steps here making the model more complicated than it might need to be.  Why do we need to POST to the web server?  After all, is it not essentially acting as an intermediary between the browser and the data source?  Is it possible to remove the web server from this model?

WCF Data Services and the Open Data Protocol (OData) combined with JQuery make it possible to remove the web server from our web application searching a remote data source scenario.  If you are unfamiliar with WCF Data Services and OData there is plenty of material elsewhere that I won’t attempt to regurgitate here, http://msdn.microsoft.com/en-us/data/aa937697.aspx is a good primer, OData itself has a comprehensive site at http://www.odata.org/.

That’s the introduction finished with, let’s look at an example using the Netflix OData service (http://developer.netflix.com/docs/oData_Catalog).

Code Snippet
  1. $(document).ready(function() {
  2.  
  3.     $("#searchForm").submit(function() {
  4.  
  5.         $.ajax({
  6.             url: "http://odata.netflix.com/Catalog/Titles?$top=10&$callback=ajaxCallback&$format=json",
  7.             dataType: "jsonp",
  8.             success: ajaxCallback,
  9.             jsonpCallback: "ajaxCallback"
  10.         });
  11.  
  12.         return false;
  13.     });
  14.  
  15.     function ajaxCallback(result) {
  16.  
  17.         $("#results").empty();
  18.         for (var i = 0; i < result.d.length; i++) {
  19.             $("#results").append("<strong>Name:</strong> " + result.d[i].ShortName + "<br/>");
  20.             $("#results").append('<strong>Genres: </strong> <a href="' + result.d[i].Genres.__deferred.uri + '">here...</a><br/>');
  21.             $("#results").append("<strong>DateModified:</strong> " + result.d[i].DateModified + "<br/>");
  22.             $("#results").append("<strong>Type:</strong> " + result.d[i].Type + "<br/>");
  23.             $("#results").append("<strong>Synopsis:</strong> " + result.d[i].Synopsis + "<br/><br/>");
  24.         }
  25.     }
  26.  
  27. });

 

Here I’ve set up a very basic page containing a form to search with and an empty div to display the results in.  Using JQuery to hook into the submission of the form I’ve set up a fairly standard ajax call that will get the top 10 Titles from the Netflix catalogue.  Because the Netflix OData service is on a different domain to my script I need to use JSONP to call it.  This is where the added url complexity comes from, if the service was on the same domain as my script the url would be much simpler (e.g. “http://odata.netflix.com/Catalog/Titles?$top=10&$format=json”) and we would not need to specify the jsonpCallback parameter.  I specify a success callback function to do something with the JSON result, I simply spit out a few properties to screen in the results div – but it’s easy to imagine more funky examples! Finally I return false to prevent the standard form submission from occurring.

If you look into the OData protocol you will notice that there are many many things that can make up the url:- $filter, $orderby, $skip, $expand, $select and $inlinecount come to mind in addition to the possibility of calling service operations.  This makes handcrafting the url potentially complex and time consuming.

After a quick bit of research I discovered a small OData plugin that already exists for JQuery - http://wiki.github.com/egil/jquery.odata/.  It removes the need to handcraft the urls – replacing them with more intuitive function calls – as well as hiding the potentially nasty ajax call setup.

Code Snippet
  1. $(document).ready(function() {
  2.  
  3.     $("#searchForm").submit(function() {
  4.  
  5.         $.odata("http://odata.netflix.com/Catalog/", { dataType: 'jsonp' })
  6.             .from("Titles")
  7.             .top(10)
  8.             .query(odataCallback);
  9.  
  10.         return false;
  11.     });
  12.  
  13.     function odataCallback(result) {
  14.  
  15.         $("#results").empty();
  16.         for (var i = 0; i < result.data.length; i++) {
  17.             $("#results").append("<strong>Name:</strong> " + result.data[i].ShortName + "<br/>");
  18.             $("#results").append('<strong>Genres: </strong> <a href="' + result.data[i].Genres.__deferred.uri + '">here...</a><br/>');
  19.             $("#results").append("<strong>DateModified:</strong> " + result.data[i].DateModified + "<br/>");
  20.             $("#results").append("<strong>Type:</strong> " + result.data[i].Type + "<br/>");
  21.             $("#results").append("<strong>Synopsis:</strong> " + result.data[i].Synopsis + "<br/><br/>");
  22.         }
  23.     };
  24.  
  25. });
  

JQuery.OData makes it much easier to work with OData services but still allows you pass through many options as per normal JQuery plugin patterns, above I pass through a dataType property set to JSONP to be used in the ajax call.  The success callback is pretty much identical, JQuery.OData does wrap up result.d into a more friendly result.data.

We’re currently using this plugin in a project at iMeta and have been pleased with it so far.  If you find yourself with the need call an OData service and don’t want to perform full page postbacks, I thoroughly recommend giving JQuery.OData a go! 

If you’re unfortunate enough to be supporting IE6 then give me a ping as I’ve spent many an hour so far debugging it and had to make a couple of tweaks to get JQuery.OData to play nice with it.

Other than that, the Fiddler web debugging tool is your friend when working with OData services, studying the request and response headers has proved to be a vital skill.

posted @ 8/26/2010 11:53 PM by Mike Godfrey

Speeding up Visual Studio Build Times and Performance

 

Our product solution build times have been getting progressively slower as more assemblies and features have been added.

We did the following:

  • Made all our build output go to one folder, main assemblies to one folder, test assemblies to another. This made about a 5x performance improvement as VS didn’t need create copies of dependent assemblies for each assembly built.
  • Split solution into component area’s and just reference Assemblies. This allows us to run VS with only a few projects, with a limited number of projects VS is now usable. Although this doesn’t improve the overall build time it significantly improves component build times when only developing within one component area.

 

This following points are important when trying to achieve the above:

  • Re-sharpers navigate to command helps here as you can navigate to the assemblies source code found from the symbol files directly.
  • All build output goes to $(solutionroot)/bin and $(solutionroot)/testbin regardless of the configuration, so different configurations still work when using an assembly reference.
  • The automated build process references each different solution via the SolutionToBuild item group, so we don’t need to maintain assemblies in more than one solution, i.e. there isn’t one solution that builds everything.
  • The Team build agent does search its own output folders for dependent assemblies, so you don’t need to copy them from the team build output to the location other assemblies are referencing them from.
  • When you have multiple solutions with dependencies between them it appears you cannot perform a parallel build, at least the team build agent cannot. I added the <BuildSolutionsInParallel>false</BuildSolutionsInParallel> property to the property section of the team build .proj file which disabled this behaviour allowing the solutions to be build in the correct order. Interestingly I had upgraded my machine to run a the RC of VS 2010 which appears to have altered the team build targets file (its different to the VS 2008 sp1 build file present on the build boxes), when I locally built the team build project with the /m switch passed to msbuild for parallel builds it succeeded.
  • Other advantages include keeping assembly dependencies from creeping over their component boundaries, i.e. if a solution only contains assemblies for one component area you can’t accidentally add references to assemblies outside that component area.
  • Splitting the solution up has a massive speed improvement when using VS, i.e. going from un-usable to usable.

posted @ 8/23/2010 4:26 AM by James Allderidge

Installing VS2008 SP1 breaks Team Build Agent

 

I installed VS 2008 SP1 on our build box running a TFS 2008 Build agent which broke the build process. Every build failed with the following error:

C:\Program Files\MSBuild\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets(300,15): error MSB4131: The "Reason" parameter is not supported by the "GetBuildProperties" task. Verify the parameter exists on the task, and it is a gettable public instance property.

In installing the SP1 update the team build targets had been updated at “Program Files\MSBuild\Microsoft\VisualStudio\TeamBuild\Microsoft.TeamFoundation.Build.targets” but the team build tasks assembly used by team build agent wasn’t updated so there was a mismatch between the .

The task assembly location is “\Program Files\TeamBuildServiceFromTFS2008\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.Build.Tasks.dll", i.e. the TFS build client install. The VS 2008 SP1 has updated the team build targets file but not the team build agents assemblies (its updated a copy of the same task, in the VS installation instead)

To get the team build agent working again I had to install the TFS server SP1 which can be downloaded from:

http://www.microsoft.com/downloads/details.aspx?familyid=9e40a5b6-da41-43a2-a06d-3cee196bfe3d&displaylang=en

 

 

posted @ 8/23/2010 3:21 AM by James Allderidge

ASP.NET Web Service and Integrated Windows Authentication only working with IP address

 

We have an issue on a customer deployment where our web service can only be accessed when communicating using the IP address in the URL rather than the host name. We are using integrated windows authentication to pass the users windows credentials so we can automatically log the user into our application. The application itself is a windows form app using dot net 2 web proxies to access asp.net web services.

In our environment accessing the services using a host name is fine but in the clients environment accessing via the host name fails, but IP address access succeeds. In short it appears the issue surrounds the interplay between Kerberos and NTLM authentication. The main reason our test environment is different to the clients environment is that they run the web services as a specific domain user and not NETWORK_SERVICE, when you do this Kerberos will not work out of the box.

In short the following links show how the clients deployment environment can be changed to work with domain names when not running the app pool as network service, either by turning of Kerberos authentication off, or by fixing it properly using Service Principle Names (SPNs)

Essentially NTLM is always used when communicating via an IP address (Wikipedia NTLM), this would explain why accessing the web service via an IP address works.

To change the authentication and to turn NTLM and Kerberos authentication on.

http://support.microsoft.com/kb/215383

To turn it off and the reason why:

http://piers7.blogspot.com/2007/04/disable-kerberos-on-windows-2003-using.html

Fixing by using a SPN

http://support.microsoft.com/?id=929650

Investigation in our environment

The following text records the investigation in our test environment surrounding the asp.net web service running as a domain user or NETWORK_SERVICE account.

The domain controller sees a logon event when talking to a web service not using network service as a user, but this doesn’t show any issue, in general I didn’t see an events in the domain controllers security logs that show the issue:

image

There are no logon events when communicating to a web service using network service.

The Application server has the authentication methods set to: “Send LM & NTLM – user NTLMv2 session security if negotiated” was ''Send NTLM response only on our test environment”. Potentially its what the setting is set in the client that counts here, this has no effect on choosing between Kerberos and NTLM though.

Communicating to the IP address;

No clients can connect to the web service when using the IP address for some reason, the exact opposite of the clients environment. Potentially NTLM is broken for us and Kerberos is the only thing that is working, our test environment is running in a VM environment with its own DC and network, the client and app servers though are also connected to our main network to make RDP easy, potentially this is causing issues and definitely an area to investigate.

Coms Traffic

DNS Name, Network Service

Response 401

WWW-Authenticate: Negotiate

WWW-Authenticate: NTLM

 

Request

Authorization: Negotiate YIIE0QYGKwYBBQUCoIIExTCCBMGgJDAiBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICCqKCBJcEggSTYIIEjwYJKoZIhvcSAQICAQBuggR+MIIEeqADAgEFoQMCAQ6iBwMFACAAAACjggOpYYIDpTCCA6GgAwIBBaEKGwhDUzAyLkNPTaIlMCOgAwIBAqEcMBobBEhUVFAbEmNzMDJhcHAwMS5DUzAyLmNvbaOCA2UwggNhoAMCARehAwIBDKKCA1MEggNP4AAuMFXJKP79YjQoyhaQKaG5Iwmmk8dFvKK/gb+78ZYUZRkZ42S+gNrfETPNJhufN2CGFwyJ9PIBmk0Ra7FIkZrJPLPHcBN97M46O1VOQtJdYYX0XvpdgrjEtuCobGAI43gKEMfGBaSZ1lt5Pi7xpNo1xN76/pgq+4vJvQ+SnOGPLgTRk/lSoVXyX3zJ5UJSmROSsAD46RU6eIQ+pNR8+NjZvd5sclQ8P/L/y62UKFcWKZA2ppVghIrQd1kmvgfip4EdR1/Apf+rT8gvgqxPuSHhfdL/kaQRWjY0dvdCKlxszytF2HQN1wYl/6ECezfeuejwtljVfSjzuAsnhjE2aESJpmXohoTiPD1HD8Hsa6Je8y7WLHyh8+DVoVJzLXPBRg/FxPxrsq1YL/KOJnx9+y9sPwUwMci621Fd571Me+I531YOCPMEQG0APOZR7zGTQRaWMQN602zsh9AKeFcUhcAvDHBPvHzeQ7m5YeOUHNIEH3lrnD8NV5UOqHePZunsHLV9aiehaUtT6rrpjOvVQ1tuvopwph7UE/PStfjLDeG1ClHWlTo8vKdYVaL1w7ktnwhifw/oqd4AiChwe6NIcuFAnvTG1eWoUPcVMHnknPSk6tmclYqn3iDKqnfw52VNoE1f8aRldCWm4hqgnUPbA6+5Z7oWzBy7sxsqE3xaJcsIxeOeeplcEyF7MYQfwo0D5RofHEN2qU+MG/oMCDpMm6zyK7HJXIiAEJh81rb53c9MdAl9aC8X/oUF2x36ntau2KUmm35Wt0QCL5qpjLdMFqYowWzQkogoVykBNUPVeYaaFdYpx/uuRMhWgM9k+8YridLAs+UX4ToJ456Zszk88UiUV7bIQU5LZGg9UDnBQzXSequLcUqD87CVhZb0tTzT7R6JRW9gkkij5tvMCBt8ab4xhhzOz++jPnmLJMSlOwujCNKgD3B0gzMlVHafDJmG3OBbVg3wuXLX5CDqJ4hZh1kpku2bj4mQvD1ZD+Bo+XTkrUCx4gCZAGr/vgizCjQDt4hEz83/9sD+FQP7Phwcfzx3AkWyg01Tb22n8KcF5bg/oy6I30t0eOr/llHtf/spc6PYVY5BZyIqsC7wv9RWaJfPvoTt/MYuni7wlL5zdaSBtzCBtKADAgEXooGsBIGpWy0v1ywq0PMWh3Q6HdKAgMZq4HJASGqCT+Ccg4wIRNnlVYsoEz822J0DdcB3qaxXIX1NcOKIR5Xcds9yJGOR1imL8YHCJX3DsMGqfs4XUBVzF5Y+SGG43/XL7++ERITTbSFzTpwsS82EylwvOEyyAyC96golat9VSJTy3fbzisgGpZn+M4wGeiCOdJz7bS38Xhl+jPkKZpQtb0wDG1juJf4QvSAXFrzPUA==

 

Response 200

WWW-Authenticate: Negotiate oYGgMIGdoAMKAQChCwYJKoZIgvcSAQICooGIBIGFYIGCBgkqhkiG9xIBAgICAG9zMHGgAwIBBaEDAgEPomUwY6ADAgEXolwEWoZdDKSN9Xs6Da1N/G/a/wB0aW1V47bz9OpCwXBnHxTx0tPGrxhI7474Nbg1zaLrIJvOorUSE/q010CuG0t0xYoHIbkirCFcK6LrQgAkXIuyEgkvrTJ+Rl+TBg==

No logon events

 

IP Address, Network Service

Response 401

WWW-Authenticate: Negotiate

WWW-Authenticate: NTLM

 

Request –> 401

Authorization: Negotiate TlRMTVNTUAABAAAAt4II4gAAAAAAAAAAAAAAAAAAAAAFASgKAAAADw==

Response

WWW-Authenticate: Negotiate TlRMTVNTUAACAAAACAAIADgAAAA1gonihXsqEfDBUGoAAAAAAAAAAHYAdgBAAAAABQLODgAAAA9DAFMAMAAyAAIACABDAFMAMAAyAAEAEgBDAFMAMAAyAEEAUABQADAAMQAEABAAQwBTADAAMgAuAGMAbwBtAAMAJABjAHMAMAAyAGEAcABwADAAMQAuAEMAUwAwADIALgBjAG8AbQAFABAAQwBTADAAMgAuAGMAbwBtAAAAAAA=

 

Request –> 401

Authorization: Negotiate TlRMTVNTUAADAAAAGAAYAHYAAAAYABgAjgAAAAgACABIAAAADAAMAFAAAAAaABoAXAAAABAAEACmAAAANYKI4gUBKAoAAAAPQwBTADAAMgBhAGQAbQBpAG4AMQBDAFMAMAAyAEQARQBTAEsAVABPAFAAMAAxAA7a339UA42oAAAAAAAAAAAAAAAAAAAAAAn8jU3tc3kILSb0cqGJjoiOlOdOcU8Le9CGQnUdqskW6W9Z5Fd4R5g=

Response

WWW-Authenticate: Negotiate

WWW-Authenticate: NTLM

 

Similar requests when not using network service, the second is a 401 with

Request

Authorization: Negotiate YIIE0QYGKwYBBQUCoIIExTCCBMGgJDAiBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICCqKCBJcEggSTYIIEjwYJKoZIhvcSAQICAQBuggR+MIIEeqADAgEFoQMCAQ6iBwMFACAAAACjggOpYYIDpTCCA6GgAwIBBaEKGwhDUzAyLkNPTaIlMCOgAwIBAqEcMBobBEhUVFAbEmNzMDJhcHAwMS5DUzAyLmNvbaOCA2UwggNhoAMCARehAwIBDKKCA1MEggNP4AAuMFXJKP79YjQoyhaQKaG5Iwmmk8dFvKK/gb+78ZYUZRkZ42S+gNrfETPNJhufN2CGFwyJ9PIBmk0Ra7FIkZrJPLPHcBN97M46O1VOQtJdYYX0XvpdgrjEtuCobGAI43gKEMfGBaSZ1lt5Pi7xpNo1xN76/pgq+4vJvQ+SnOGPLgTRk/lSoVXyX3zJ5UJSmROSsAD46RU6eIQ+pNR8+NjZvd5sclQ8P/L/y62UKFcWKZA2ppVghIrQd1kmvgfip4EdR1/Apf+rT8gvgqxPuSHhfdL/kaQRWjY0dvdCKlxszytF2HQN1wYl/6ECezfeuejwtljVfSjzuAsnhjE2aESJpmXohoTiPD1HD8Hsa6Je8y7WLHyh8+DVoVJzLXPBRg/FxPxrsq1YL/KOJnx9+y9sPwUwMci621Fd571Me+I531YOCPMEQG0APOZR7zGTQRaWMQN602zsh9AKeFcUhcAvDHBPvHzeQ7m5YeOUHNIEH3lrnD8NV5UOqHePZunsHLV9aiehaUtT6rrpjOvVQ1tuvopwph7UE/PStfjLDeG1ClHWlTo8vKdYVaL1w7ktnwhifw/oqd4AiChwe6NIcuFAnvTG1eWoUPcVMHnknPSk6tmclYqn3iDKqnfw52VNoE1f8aRldCWm4hqgnUPbA6+5Z7oWzBy7sxsqE3xaJcsIxeOeeplcEyF7MYQfwo0D5RofHEN2qU+MG/oMCDpMm6zyK7HJXIiAEJh81rb53c9MdAl9aC8X/oUF2x36ntau2KUmm35Wt0QCL5qpjLdMFqYowWzQkogoVykBNUPVeYaaFdYpx/uuRMhWgM9k+8YridLAs+UX4ToJ456Zszk88UiUV7bIQU5LZGg9UDnBQzXSequLcUqD87CVhZb0tTzT7R6JRW9gkkij5tvMCBt8ab4xhhzOz++jPnmLJMSlOwujCNKgD3B0gzMlVHafDJmG3OBbVg3wuXLX5CDqJ4hZh1kpku2bj4mQvD1ZD+Bo+XTkrUCx4gCZAGr/vgizCjQDt4hEz83/9sD+FQP7Phwcfzx3AkWyg01Tb22n8KcF5bg/oy6I30t0eOr/llHtf/spc6PYVY5BZyIqsC7wv9RWaJfPvoTt/MYuni7wlL5zdaSBtzCBtKADAgEXooGsBIGpQLxhefwgE1t2sjQg+R0KYIhuUh2YhsdAXNmqkDt8dYVY+vczAA5UGPoghBgoPDdD/RAcF1I8XQMNaMQRwVfI+MGLxL6kVGtUbnizUf7o1jmDfvZ09+9TZqnqUXuMDd+IpvgnWI5K5bI6M4PWeDY9Exk2GmVlxBZ3pCREkcE/ke2A53CaZ6dF8OGEbSWWd4x/ec5EqxqeyfAvbsfxaJ6nnh9BK7msOMQBzw==

Response

WWW-Authenticate: Negotiate oYGIMIGFoAMKAQGhCwYJKoZIgvcSAQIConEEb2BtBgkqhkiG9xIBAgIDAH5eMFygAwIBBaEDAgEepBEYDzIwMTAwNzEyMDk1MzQ4WqUFAgMGSpSmAwIBKakKGwhDUzAyLkNPTaolMCOgAwIBA6EcMBobBGhvc3QbEmNzMDJhcHAwMS5jczAyLmNvbQ==

and a following request with

Authorization: Negotiate oYIEnzCCBJuiggSXBIIEk2CCBI8GCSqGSIb3EgECAgEAboIEfjCCBHqgAwIBBaEDAgEOogcDBQAgAAAAo4IDqWGCA6UwggOhoAMCAQWhChsIQ1MwMi5DT02iJTAjoAMCAQKhHDAaGwRIVFRQGxJjczAyYXBwMDEuQ1MwMi5jb22jggNlMIIDYaADAgEXoQMCAQyiggNTBIIDT0yHCikaYn0FY3dNwR4Eo4ma+tiJpbeAiiDkjMnpGzphbxn5OryeeIzoPxOHd2o84uEOlAl2dpTBGpZ5YxFbO3o4BFFIUcATEX5TiORQVuYO606oywDlIXjow6rz8N6HyITZm/CLmCXOXG0zrtSldD6QcQ5hTP5A7NlPGSl16ULaDTobBi9lRvpvn6kIM4BRWOJyNQmtUqXRV8vjkuodnbDFhxieRwy3QhD+HqVja+Kqwcw1nEhnWHEsUhw+31WFFbH1g0bD212xQBW7SflrTw6YF8laFa80AbU8QqkgDXcTFj6FmHBwb87NbSNkPZrOGKVBVN8VEc+L1fy5i41q+hogihLYXVtLTrO7tvYW4NmWa6T+2K2cft1GI9HZLmPJBKpX7sggb9pvYnH0I6jsbjQvjV8203eToCPI+doN0pc/ba4RhjHvIDcjtHkhpEe3kvpcYhYZfdQax4wat1Zaeqomqlaf4TqMukEYctLt5x/NpC4ETVnzgbUalOU3wUrE03l4AyMpUu6n/GREgDzyfri8IaQNGbeR9AnUUvf/M6SwEc1OABmdDdAdi+9h1xMlHcBClP+EsXfDJghzez/bp1iuQWv3EzgsnMKmLX6MinDyjjVxyPacYtgZGswUfdlXwbRPpQ4s3VWYfyHPYltrGSFZgRBccQE6Dj9Y6I/WSz1dhIcqDMIRx+8AaiAeujpDBa4dtR8fKhzvkx5AGJpGn7feRena2wznjU+4H9rt6jeA2Y+3Wh8dcfBUYk/CqBvciN1DdPXtf/vNCszlo6wf5VGGPxk49Lhj7OfKdGWmEGNXbqM4ReOQgImKvLk4plqn2BLLW6Up+KVCXivibx9+HCSuMc36n0WonsCGh4U21iTS8Yg49xFQ4LeShdjt/Ds8gfv85nBcho6jINXkq2v4xuQDSs0C8T58oVN5p4Zof3M80o2AaoNr3vkLZ1pTqXDjk8jH+YYz15E+UOO4TWvdShT5f6kcLUebGFHQiamO+8nSagwYbTWRL1JH+GbrFQCf2ffv2GJEYqBakQW96CwbxVZqIrMFAMt/QBfvUj7LUFMS/DaHrTajvAlHui2G6y86S+c2ykgOMMXSe6N+3rNej9faF0zp0Axmij+gNfi01lekgbcwgbSgAwIBF6KBrASBqcEFv86hjFvokwjI5uDEI4oYOLSnfoZk2Eb4NWWU30+a5hSqiDpCjaVjs4+SQWA6ZhIM/f6IePTMLD86qCP9/9QTvkD3tlwwFrzEOc3vWxP1fNM9rGrAmVyzUAXaZMrvLTz+in9/1wsBKllcQeuc3TMk2GFjzmFMmVO5trX9fQB2dWkfcRh31RC9bVJb87BqUkYc4iBjjpf9rZvOQjJIMypnxhLxbDg69ek=

Then the ending response with the two types of www-authenticate only.

posted @ 7/18/2010 9:56 PM by James Allderidge