Marc Melvin’s Blog

.NET

Programmatically Merging a ResourceDictionary from Another Assembly

by Marc Melvin on Jan.27, 2010, under WPF

I recently had to find a way to merge a ResourceDictionary that is embedded in a class library into my application’s MergedDictionaries collection, so this is how I did it. I created the following extension method:

?View Code CSHARP
    static public class ExtensionHelpers
    {
        static public void AddAssemblyResource(this Application app, string assemblyName, string path)
        {
            if (!UriParser.IsKnownScheme("pack"))
                UriParser.Register(new GenericUriParser(GenericUriParserOptions.GenericAuthority), "pack", -1);
 
            ResourceDictionary dict = new ResourceDictionary();
            Uri uri = new Uri("/" + assemblyName + ";component/" + path, UriKind.Relative);
            dict.Source = uri;
            app.Resources.MergedDictionaries.Add(dict);
        }
    }

Then, to add my resource, I simply call

?View Code CSHARP
App.Current.AddAssemblyResource("My.Assembly.Name", "Path/To/Resource.xaml");
1 Comment more...

The Easy Way to Debug Windows Services in Visual Studio.NET

by Marc Melvin on Nov.12, 2008, under .NET

I’ve been told several times in the past that I have a unique way of debugging .NET Windows services. While most of my colleagues go through the typical process of building, installing, and attaching to the process, I find it much easier to just hit F5 and be done with it. I have a very precise way of doing this that makes it extremely easy.

  1. Create a new Windows service project the same way you normally would in Visual Studio.
  2. When debugging our Windows service project in Visual Studio, we want to open a console window that can be used for outputting debug messages. Create a helper class called ConsoleHelper (I usually do this in a common shared library that I reuse in all my projects) that looks like this:
    ?View Code CSHARP
    static public class ConsoleHelper
        {
            [DllImport("kernel32.dll")]
            private static extern int AllocConsole();
            [DllImport("kernel32.dll")]
            private static extern int FreeConsole();
     
            static public void OpenConsole()
            {
                AllocConsole();
            }
     
            static public void CloseConsole()
            {
                FreeConsole();
            }
        }
  3. Because we will be running our service as somewhat of a “console” application in debug mode, the typical service start/stop routines won’t be called the same way. Since they default to having protected modifiers, we will modify our service by adding internal Start() and Shutdown() methods, and ensure that the service overrides for OnStart() and OnStop() just call these new methods we are creating for when it actually runs in release mode. I also like to put the overrides in a region so I can hide them away from view and to keep me from adding code to them by accident. All of my service code will go in Start() and Shutdown() now, so I don’t really need them any more. Open the code view of your Service1.cs file and make it look something like this:
    ?View Code CSHARP
    public partial class Service1 : ServiceBase
        {
            public Service1()
            {
                InitializeComponent();
            }
     
            internal void Start()
            {
            }
     
            internal void Shutdown()
            {
            }
     
            #region ServiceBase Overrides
     
            protected override void OnStart(string[] args)
            {
                Start();
            }
     
            protected override void OnStop()
            {
                Shutdown();
            }
     
            #endregion
        }
  4. Now, we need to replace the entry point of the application to support the special case for when we are running in debug mode. Open the Program.cs file and find your main() method. Find the code that looks like this:
    ?View Code CSHARP
    ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]
    			{
    				new MyService()
    			};
                ServiceBase.Run(ServicesToRun);

    And replace it with this (make sure your service class names actually match your service classes instead of MyService):

    ?View Code CSHARP
    #if !DEBUG
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]
    			{
    				new MyService()
    			};
                ServiceBase.Run(ServicesToRun);
    #else
                ConsoleHelper.OpenConsole();
                Console.WriteLine("Server-side service started. Press ENTER to stop service.");
     
                try
                {
                    MyService service = new MyService();
                    service.Start();
                    Console.ReadLine();
                    service.Shutdown();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
                    Console.ReadLine();
                }
     
                ConsoleHelper.CloseConsole();
    #endif

    If you run this now in debug mode, you will see a debug window popup, and your “service” will be running very similarly to how it would run if it were actually installed. However, there are a few more things we still need to do, so let’s press on.

  5. We still need to take care of adding the typical service installer to our service. To do this, open the Service1.cs file in design view. When the component designer appears, right click anywhere in the designer and choose “Add Installer.” This will create our ProjectInstaller.cs component.
  6. Last, we want to make sure that no one accidentally installs a debug build of this service as it will do some very funky things. Not only will it let you install it, but it will appear to actually be working (and then “fail gracefully” with a ridiculous error that makes you think your code is wrong when it isn’t). To do this, we need to add an Install() override to the ProjectInstaller class that will throw an exception when an install is attempted in debug mode. Open up ProjectInstaller.cs in code view and change it to look like the following:
    ?View Code CSHARP
    [RunInstaller(true)]
        public partial class ProjectInstaller : Installer
        {
            public ProjectInstaller()
            {
                InitializeComponent();
            }
     
            public override void Install(IDictionary stateSaver)
            {
    #if DEBUG
                throw new ApplicationException("You cannot install the debug version of this service.");
    #else
                base.Install(stateSaver);
    #endif
            }
        }
  7. Ok, I lied. There is one more cool thing we can do which I will leave as an exercise for the reader. We can create a static Log class to log any event we want throughout our service code. In release mode, we might use this to log our message to the Windows event log or send a horrible annoying email to the developer (remember, that’s YOU!). In debug mode, we can just write our message directly out to the console and our ConsoleHelper window will pick it up automatically. Yay for programming!
Reblog this post [with Zemanta]
2 Comments :, , , , , , , , , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Archives

All entries, chronologically...