Showing posts with label C# Guidelines. Show all posts
Showing posts with label C# Guidelines. Show all posts

Sunday, August 09, 2015

Generating Resource Designer Files During Build with Visual Studio

In Visual Studio files containing resources have the extension *.resx. As you edit this file VS will use a custom tool to generate a strongly typed *designer.cs file. However, since this is a generated file, you should not need to put it under version control. Consequentially you will need to generate the file. One option is to use the context menu and select "Run Custom Tool". This is cumbersome if you check out the code base and have many resource files. It would be great, if those designer files were created automatically when building the project.

Another scenario is where resource files are re-used across multiple projects. Here, too, automatic generation during build would be useful.

Finally it would be great if a solution for automatically generating the designer files would work for both building the project in Visual Studio and building it via msbuild at the command line.

The solution presented here was developed with Visual Studio 2013 and C#. It may or may not work in other environments.

To automatically generate the *.designer.cs files from *.resx files, follow these steps:

1. Close your solution

2. Open as an XML file the project file in which you want to automatically generate the designer files. Note that you need to load it as an XML file. You can't edit these settings through the project property page.

3. Add a target to the project as follows:

<Target Name="GenerateDesignerFiles">
   <Message Text="Deleting old Designer Files..."/>
   <Delete Files="@(EmbeddedResource->'%(RootDir)%(Directory)%(Filename).resources')"/>
   <Delete Files="@(EmbeddedResource->'%(RootDir)%(Directory)%(Filename).designer.cs')"/>
   <Message Text="Generating Designer Files..."/>
   <GenerateResource
      Sources="@(EmbeddedResource)"
      StronglyTypedLanguage="C#"
      StronglyTypedClassName="%(Filename)"
      StronglyTypedNamespace="@(EmbeddedResource->'%(CustomToolNamespace)')"
      StronglyTypedFileName="@(EmbeddedResource->'%(RootDir)%(Directory)%(Filename).designer.cs')"
      PublicClass="true"
      >
   </GenerateResource>
   <Message Text="Generating Designer Files complete."/>
</Target>

4. Locate the target named "BeforeBuild". This target may be commented out (the default).

5. Modify the "BeforeBuild" target as follows:

<Target Name="BeforeBuild">
   <CallTarget Targets="GenerateDesignerFiles"/>
</Target>

This solution is based on all resource files being listed as "EmbeddedResource" within an ItemGroup of the project file, e.g.

<ItemGroup>
  <EmbeddedResource Include="Resources\Creditor\Display_Creditor.resx">
    <Generator>PublicResXFileCodeGenerator</Generator>
    <LastGenOutput>Display_Creditor.Designer.cs</LastGenOutput>
    <CustomToolNamespace>Acme.Web.Resources.Creditor</CustomToolNamespace>
  </EmbeddedResource>
  <EmbeddedResource Include="Resources\InboundEmail\Tooltip_InboundEmailDetails.resx">
    <Generator>PublicResXFileCodeGenerator</Generator>
    <LastGenOutput>Tooltip_InboundEmailDetails.Designer.cs</LastGenOutput>
    <CustomToolNamespace>Acme.Web.Resources.InboundEmail</CustomToolNamespace>
  </EmbeddedResource>
  <EmbeddedResource Include="Resources\Creditor\Tooltip_CreditorDetails.resx">
    <Generator>PublicResXFileCodeGenerator</Generator>
    <LastGenOutput>Tooltip_CreditorDetails.Designer.cs</LastGenOutput>
    <CustomToolNamespace>Acme.Web.Resources.Creditor</CustomToolNamespace>
  </EmbeddedResource>
</ItemGroup>

Disclaimer: This has been tested with Visual Studio 2013 and C# projects. It also works using msbuild. It may or may not work for other environments.

Saturday, April 21, 2012

ASP.NET: Base Directory and Developer Tests

Assume that in your ASP.NET application you need to access a file that is part of the deployed web site. On the other hand you would like to also run some developer tests.

The way I like to organize developer tests is putting them in a separate project and a separate assembly. For example for an ASP.NET project “MySite” I would have a second project called “MySite.Tests”. In the test project I then reference the “MySite” project which gives me direct access to all code inside of “MySite”. Typically give all projects a strong name and therefore can make internals of “MySite” visible to code in “MySite.Tests” by placing the InternalsVisibleToAttribute on the “MySite” assembly.

The challenge now with accessing the file is that depending on whether they are run from within an ASP.NET server (IIS or WebDev.WebServer) or within a unit test runner, finding the root folder (or base directory) can be tricky in some cases.

For example we could use a solution based on the MapPath method of the HttpContext.Current.Server object. This is described in more details in an answer on StackOverflow and works when an HttpContext is available. When the same code is run in a unit test runner HttpContext.Current is null (Controller.HttpContext in MVC), so this solution wouldn’t work.

The solution that I have chosen and that works so far is based on the application domain. The following code is all that is required and it works in both IIS, WebDev.WebServer as well as when executed within a unit test runner:

var domainRoot = AppDomain.CurrentDomain.BaseDirectory;
var configFile = Path.Combine(domainRoot, Common.DbSettingsFile);

Happy coding!

Tuesday, November 22, 2011

DirectoryInfo.Delete() when files are read-only

DirectoryInfo.Delete() will fail with UnauthorizedAccessException if that directory or any of its subdirectories contains a file that is read-only.

One solution is to remove the read-only attribute from all files. You can do so while recursively deleting directories. This approach is mentioned in some blogs and it looks as follows:

public static void RecursivelyDeleteDirectory(
                   DirectoryInfo currentDirectory) {
   try {
      currentDirectory.Attributes = FileAttributes.Normal;
      foreach (var childDirectory in 
                        currentDirectory.GetDirectories()) {
         RecursivelyDeleteDirectory(childDirectory);
      }

      foreach (var file in currentDirectory.GetFiles()) {
         file.IsReadOnly = false;
      }

      currentDirectory.Delete(true);
   }
   catch (Exception ex) {
      Console.WriteLine(ex); // Better option: Use log4net
   }
}

While this works some people do not like recursion. So here is an option for how the same can be achieved without recursion:

public static void DeleteDirectory(
                   DirectoryInfo currentDirectory) {
   try {
      foreach (var file in currentDirectory.GetFiles(
               "*", SearchOption.AllDirectories)) {
         file.IsReadOnly = false;
      }
      currentDirectory.Delete(true);
   }
   catch (Exception ex) {
      Console.WriteLine(ex); // Better option: Use log4net
   }
}

Please note that these implementations report exceptions at the console. A better option would be to use a standard logging framework like log4net.

Sunday, July 31, 2011

C# Guideline: Use String.Empty When You Can

Whenever you are tempted to write “” as a string somewhere in your C# code use String.Empty instead. What is the difference? Technically one is a constant while the other is a read-only static field. There is no difference in behavior in this case. However be aware that both are different in their implementation.

The inline constant “” is introduce at compile time. This means once it has been compile it cannot be changed any more.

With the read-only field it is a little different. During compile time only a reference to the field is added. This value of this field is then read during runtime.

This can be quite a difference. For example if the read-only property is define in a different assembly and then you update that assembly with the read-only property now having a different value, that new value will then be used from then on.

Why do I believe this is a good guideline for C#? When you add your own “constants” you typically want to define and maintain them in one place only. With a static property you can achieve that. The code then looks as follows:

public class Foo {
   public static string LastName = "Smith";
}

And here is how you then use it:

public void Bar() {
   var address = "Mr. " + Foo.LastName;
   // ... remainder left out
}

If you ever need to change the LastName value you only need to change it in one place. Although String.Empty is very unlikely to change, for consistency reasons you should use it rather than “”.

The same guideline applies to all other types of constants as well, e.g. Type.EmptyTypes.

There is (at least) one exception to the use of String.Empty. If you have a switch statement on a string and one of the cases is String.Empty you will find that it won’t compile. The ‘case’ statement requires a constant (which evaluate at compile time) and doesn’t allow for read-only fields (which evaluate at runtime). So the only option then is to write the following:

switch(aString) {
   case "": // Can't write ‘case String.Empty:’ here!
      // something important to happen here
      break;
}