October 2007

Monthly Archive

Untrusted Network shares

Posted by Chris Alcock on 30 Oct 2007 | Tagged as: .NET, C#, Design, Development, Software, SysAdmin

One of my longest standing pet hates with desktop software developed in .NET relates to the almost inevitable security exception that will occur if you attempt to run it from a network share. Its always one of the first things I notice about software, as I often download and unzip software onto my desktop (which on my work machine is located on a network share) and then attempt to run it in place. Many large and quite impressive pieces of software that get distributed as .ZIP files rather than installers suffer this plight, and a lot of them don’t handle the exception well (One that springs to mind was the much heralded release of NDepend 2.0).

The good news is that this anguish may well be about to come to an end, as Brad Abrams requests feedback about the .NET teams possible plan to make network shares trusted. As he mentions, there really is no good reason not to trust a network share for running managed .NET code - there is no such protection for unmanaged code, and there is little or no way a normal user would be aware of which is .a NET EXE and which is unmanaged EXE.

To answer Brad’s Questions:

A) Have you ever run into this limitation (a security exception when running a .NET application from a network file share)?

I frequently experience these issues - I tend to use this problem (and if its been worked round in the application) as a yard stick as to how well written the application is.

B) How often do you use network file shares for deploying applications (managed or otherwise)?

Most of my development is web based, however for utilities written for in house use we tend to distribute them on a network share - being able to run these in place would be a great help, as updating them would be easier.

C) If you think we should make this change, when would be a good time? Is it something we should do sooner in a service pack of the .NET Framework or later in a full release of the framework. Note, we are DONE with .NET Framework 3.5, so there is zero chance it is getting in that release.

From my point of view a patch as soon as possible, and have it included in the next release of the framework - Since this is a relaxation of the current restriction, I can’t see that it would cause any more problems in terms of support of existing application, as a reduction of the support incidents caused by this issue would reduce.

D) Can you ask your local network admin what they think of this issue? Would they be in favor of this sort of change? If so, when?

This change should simplify deployment - allowing Managed EXE to run from shares should mean that local disks can be more locked down as there would be no need to copy programs locally to run them.

All in all, I’m very much in favour of this change - It will level the playing field, give a more consistent user experience, and reduce the problems people have with winforms applications.

AND/OR Searches for related records

Posted by Chris Alcock on 22 Oct 2007 | Tagged as: Database, Development, SQL

A common database problem I have to explain to people is creating search functionality which allows a user to find a master record based on it having some or all of a specified set of related records.  To illustrate this, consider a database which defines products, which can each have 0 or more features from a table of features assigned to them. 

ProductFeatureDiagram

The table Product contains the details of the product (in our case, just a name - its an example after all).  A list of features are supplied in the Feature table, and the relationship between a products and a feature is expressed by a record in the ProdFeatureLink table. 

In this example, we will have 3 products, each with a different combination of the three features:

  • Product 1 has Feature 1
  • Product 2 has features 1 and 2
  • Product 3 has features 1, 2 and 3

So, to summarise the data involved we can issue the following query:

select
    p.product_key, P.ProductName, F.FeatureName
from product p
    inner join prodfeaturelink pfl on p.product_key = pfl.product_fkey
    inner join Feature f on f.feature_key = pfl.feature_fkey

This gives the following results:

ProductFeatureSimpleSelectResult

In our first case we are interested in products which have ‘Feature 1′. To find these we can use the previous query with a filter for the feature required:

select P.* from
product p
    inner join ProdFeatureLink pfl on p.product_key = pfl.product_fkey
    inner join feature f on f.feature_key = pfl.feature_fkey
where
    f.featureNAme = 'Feature1'

This gives the following result set:

ProductFeatureOnlyFeature1

This query correctly returns Products 1,2 and 3.

In the next case, we are interested in products which have any or all of two features (Features 2 and 3). Again, this can be achieved by taking our original query and adding a where clause which filters for either of the features.  This filter can be performed using ‘featureName IN (X,Y)‘ or by ‘FeatureName = X OR FeatureNAme = Y‘.

select distinct p.*
from product p
    inner join prodfeaturelink pfl
        on pfl.product_fkey = p.product_key
    inner join feature f
        on f.feature_key = pfl.feature_fkey
where
    f.featureName in ('Feature2', 'Feature3')

And here is the result set:

ProductFeatureEitherOrBoth

In order that we only get one mention of the product record the query above uses the Distinct clause, otherwise we would get duplication of results.

The final case is to find products that have both Features 2 and 3. This isn’t as simple as it might seem - we can’t just use the AND operator in place of the or, as each individual row of our original query’s results cannot contain two feature values. In order to do this, we need some new tools - specifically Group By, Having and an aggregate function or two. 

Our previous query (Feature 2 AND/OR feature 3) provides the basis - we just need a way of finding only products which have both Feature 2 and 3. We can manage this by requiring that the count of the rows for each product is equal to the number of features we are searching for. 

select p.product_key, p.productName
from product p
    inner join ProdFeatureLink pfl on pfl.product_fkey = p.product_key
    inner join feature f on f.feature_key = pfl.feature_fkey
where featureName in ('Feature2', 'Feature3')
group by p.Product_key, p.ProductName
Having Count(product_key) = 2

giving the result set:

ProductFeatureBoth

The placement of the criteria in this query is important. We must use the where to remove any data we are not interested in - so the WHERE filters our data down to only those products which have either feature 2 and 3. We then use the GROUP BY to gather up each product, and finally the HAVING checks that each product has the required number of features.

We can actually merge both the AND and the OR cases of this query together, as the only difference is that for an AND query we must have as many features against the product as we have specified, where as the OR query must have 1 or more.

declare @type char(3)
Set @type='AND'
--Set @type='OR'
select p.product_key, p.productName
from product p
    inner join ProdFeatureLink pfl on pfl.product_fkey = p.product_key
    inner join feature f on f.feature_key = pfl.feature_fkey
where featureName in ('Feature2', 'Feature3', ..., 'Feature n')
group by p.Product_key, p.ProductName
Having Count(product_key)>= CASE WHEN @type='AND' THEN n ELSE1 END

This query does rely slightly on the structure of the data involved. We rely on the fact that each product may only be assigned one instance of a feature- if a product may be assigned more than one instance of each feature then things do become a bit more difficult - but I’m going to save that for a later date.

UPDATE: Here is a SQL script of the examples used in the article:

AND/OR Searches of related records - SQL Script containing examples in the article

Relocating Temporary ASP.NET Files

Posted by Chris Alcock on 15 Oct 2007 | Tagged as: .NET, ASP.NET, Development, IIS, SysAdmin

When you first request a page from the an ASP.NET application, the .NET framework takes the ASPX file and generates code to actually execute the page. This code is then compiled by the framework and the results of the compilation are stored in the Temporary ASP.NET files directory within the framework directory (usually located in c:\windows\Microsoft.NET\Framework). When the ASPX of the compiled DLL changes this code is re-generated and recompiled.
On a server that hosts lots of ASP.NET applications this store of temporary compiled code can occupy a considerable amount of space. On machines with a limited amount of space on their OS partition this can begin to cause problems. Thankfully the ASP.NET framework does allow the location of this directory to be specified as a custom location.
As with most server wide settings you need to make a change to the Machine.Config (for .NET 1.1) or Machine wide web.Config (for .NET 2). The crucial part of the configuration is the Compilation element within system.web. The compilation element has an optional attribute called tempDirectory that allows a new directory location to be specified overriding the default setting of %FrameworkInstallLocation%\Temporary ASP.NET Files.

<system.web>

   <compilation tempDirectory="d:\TempASP.NETFiles\">

      ...

   </compilation>

</system.web>

One thing to watch out for when making this change is the file permissions on your new Temporary ASP.NET files - copying the permissions from the original location will do the trick nicely.

Invalid XML from a .NET web service

Posted by Chris Alcock on 01 Oct 2007 | Tagged as: .NET, ASP.NET, C#, Development, Web Services, XML

10187684_78f140f0e2_m.jpg
Image Credit: kevinzim on Flickr

One of my basic assumptions about the .NET framework was proved incorrect last week. Up until then, I had believed that when you are using the built in framework classes for exposing web services you were always safe when it came to the output being valid XML. Sadly that turns out to be untrue, and to make matters worse, .NET will happily output XML over a web service even its own .NET web service clients can’t read.

There are certain characters that are forbidden from being in XML as per the official specification. These characters are the low ascii characters such as NULL, EOF etc. Its important to note that this is not a case of unescaped/unencoded versions of this character being disallowed, the encoded characters are also disallowed.

The problem with this isn’t that the .NET framework doesn’t understand these rules - it manages just fine when it comes to acting as a client to a web service serving these characters in content, throwing nice exceptions explaining that these characters are invalid. Additionally, the XML Text Reader has a property ‘Normalization’ which causes the XML reader to be more liberal and ignore invalid characters - but this option is not used within the automatically generated Web Service Client.

This problem isn’t limited to just the web services, standard XML serialisation also experiences the same problems. Here are bits of code that illustrate the problem:

[WebMethod()]

public string InvalidCharacter()
{
   return "" + (char)4;
}

public class MyClass
{
   public string Test = "" + (char)0;
   public static void Main()
{
     MyClass c = new MyClass();
     System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(MyClass));
     System.Text.StringBuilder sb = new System.Text.StringBuilder();
     System.IO.StringWriter sw = new System.IO.StringWriter(sb);
     xs.Serialize(sw, c);
     Console.WriteLine(sb.ToString());
    
     System.IO.StringReader sr = new System.IO.StringReader(sb.ToString());
     try
     {
         c = (MyClass)xs.Deserialize(sr);
     }
     catch (System.Exception ex)
     {
         Console.WriteLine(ex.ToString());
}
}
}

The little console application gives output like this:

<?xml version="1.0" encoding="utf-16"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Test>&#x0;</Test>
</MyClass>

System.InvalidOperationException: There is an error in XML document (3, 12).
System.Xml.XmlException: '.', hexadecimal value 0x00, is an invalid character.
Line 3, position 12.

Unfortunately I haven’t yet found a fix for this - my only solution is to work around the problem by ensuring that these invalid characters can’t get into the system in the first place or clean the text on the get of each property of the serialized objects.

Things like this really worry me - our frameworks shouldn’t be outputting things that they can’t read - let alone outputting things that completely contravene the specifications. As always, any suggestions on an alternative solution to this problem are welcome.