Friday, February 25, 2011

The resource cannot be found error when using Dynamic Data.

Have you seen the error page shown below when you are developing a ASP.NET Dynamic Data application?

Server Error in '/' Application.

The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly.
Requested URL: /DynamicData/PageTemplates/Edit.aspx


Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1

I thought my application was broken. In the end, it had nothing to do with my application. It has everything to do with how a ASP.NET Dynamic Data Domain Service Web Application is setup by default when press F5. By default the project is setup to open the Current Page as the start action. I noticed that if I have the Edit.aspx page selected in my Solution Explorer and then hit F5 I get the error above. Notice the url in your browser, it is something like this:

http://localhost:1440/DynamicData/PageTemplates/Edit.aspx

What I wanted and expected to happen was open the default page when I hit F5. The error is 100% correct. That page is not directly available since I am using Dynamic Data.

If I select my project instead and hit F5 I get the default page as expected and desired.

So, really all this is just because I didn’t realize what the default behavior was. The remedy is very simple. Right click on Default.aspx in the Solution Explorer and select Set as Start Page. This will change the Start Action to use a Specific Page (the Default.aspx in this case) instead of the Current Page.

If you are not sure what your project is set to you can right-click on your project in Solution Explorer and go to the Web tab. Here you will see Start Action. To have F5 always start the Default.aspx page make sure Default.aspx is in the Specific Page textbox.

Here is what it should look like:

image

Wednesday, February 9, 2011

Setting default values in Entity Framework when using Silverlight

I found myself amazed at how difficult it is to set default values for a property in the Entity Framework (even version 4) when used with Silverlight. Ideally I could use the DefaultValue attribute in the metadata class for my model. The problem is that Silverlight doesn’t use it. It seems to work ok in my tests that don’t use Silverlight if I remember correctly. But that only partially helps. I explored putting the value in the constructor for the entity that has the property I want to set the default value on, but that fires every time the object is created. This means that it was created even when displaying the results of a query, which is not the event I was hoping for. I want the default value to be used when a new entity is created, but just the object instantiated.

Then I ran across this post. It talks about creating a partial class on the client-side (Silverlight) and using the partial method called OnCreated(). The forum seems to say that you can define the OnCreated() partial method in the partial entity class that is on the server-side, but that method is not defined on the server-side that I can tell. So, the partial keyword doesn’t work in that context. The server-side object has a .shared.cs instead of just .cs extension so the file will be copied to the client-side. The problem is that the code has to work on the client and the server side. As noted before, the OnCreated method only exists on the client-side.

The solution is actually quite simple. I just had to explicitly define a partial class on the client-side even though I already have one on the server-side and is shared. This allows me to leverage the OnCreated partial method on the client that will fire when the entity is created, not just instantiated, and still keep my shared partial class that is on the server and client side.

I haven’t tried it, but by doing like Kyle recommends I should be able to use the DefaultValue attribute in the metadata and have it carry over to the client-side by calling the utility method that reads the DefaultValue attribute from the model when the OnCreated method is called.

So, here is an example, of what I am trying to explain.

In this example (to keep with the example on the forum) my entity is called Entity1

In my Silverlight project, I define a file called Entity1.cs. It would contain:

public partial class Entity1
    {
        partial void OnCreated()
        {
            DefaultValueUtility.InitializeDefaultValues(this);
        }
    }

NOTE: I could also just set the property directly instead of pulling the data from the model.

I can, but don’t have to have a file called Entity1.shared.cs on my server-side that will can contain whatever I want it to. It will be copied to the client-side as well. Then it will be merged with the Entity1.cs and the generated Entity1 file from the model itself on the client side because they are all partial classes.

Here is the code for the DefaultValueUtility call above. You will want to put this code somewhere in your Silverlight project.

using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;

namespace DefaultSetter
{
    public static class DefaultValueUtility
    {
        public static void InitializeDefaultValues(object entity)
        {
            PropertyInfo[] properties = entity.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                MethodInfo propertySetter = property.GetSetMethod();
                if (propertySetter != null)
                {
                    DefaultValueAttribute defaultValueAttribute = (DefaultValueAttribute)
                        property.GetCustomAttributes(typeof(DefaultValueAttribute), true).FirstOrDefault();

                    if (defaultValueAttribute != null)
                    {
                        object defaultValue = 
                            Convert.ChangeType(defaultValueAttribute.Value, property.PropertyType, CultureInfo.InvariantCulture);

                        propertySetter.Invoke(entity, new object[] { defaultValue });
                    }
                }
            }
        }
    }
}

Thursday, February 3, 2011

Hints on how to start writing an Internet Explorer Add-on

Most of the info here are for how to write a Browser Helper Object or (BHO). A BHO is a faceless piece of code that is executes when iexplore.exe (Internet Explorer) and explore.exe (Windows Explorer) launch. Yes, believe it or not by default when you add to one, you are adding to the other. I’ll tell you how to avoid that later. You can also write toolbars, etc, but I don’t really cover that here other than some of the links at the bottom of the page do.

A BHO is the simplest plug-in you can write for IE because there is no UI, it is just sitting there allowing you to hook into IE’s events. The two most common are fired when a page has completed its loading (OnDocumentComplete), and also when navigating (OnBeforeNavigate2)  like when a user clicks the link on a page. You may also want to look at NavigateError which is called when there is an error during navigation.

There is also a RegisterBHO method that gets called when you register your BHO which is just a .dll. It is called RegisterBHO, and has a similar method called UnregisterBHO that gets called when you unregister your BHO. When I say register, I am talking about the days of COM. So, you will need to use regasm to register and unregister your BHO. regasm is included with all (I think) the Visual Studio versions. However, you will need to go to the start menu and then go to the Visual Studio 2XXX item and choose something called something like: Visual Studio Tools then Visual Studio Command Prompt (2010). This will bring regasm into the execution path. The two commands you will need are:

regasm /codebase "BHOHelloWorld.dll"

regasm /unregister /codebase "BHOHelloWorld.dll"

You would use these (or similar) to install and uninstall your BHO.

There is some code you will want to put in your RegisterBHO so that IE will see it and load it on startup. Basically, your code will need to get the GUID that you assigned to your BHO class using the Guid attribute, and then add a new SubKey to

HKLM\Software\\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects

If you don’t want the BHO to be used by Windows Explorer and thus only by Internet Explorer, you need to Add a NoExplorer Key at the following path where <GUID> where <GUID> is the GUID for you BHO and also the SubKey your code should have added to the above path in the registry.

HKLM\Software\\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\<GUID>\NoExplorer

Set that value to the number 1. If you don’t do this before you register your BHO, you will need to re-register it so that the code will be executed when it registers or just add it manually. Regardless, you may find that after a reboot (or sooner) that Windows Explorer has loaded your BHO and won’t let you build (if you registered the .dll in your bin directory that you are building to). In that case, un-register the .dll, and logout and log back into Windows. Now you should be able to build again. You will always need to have IE closed when you are building also.

I would recommend going to here and downloading this project and opening it. Before you run it, change the RegisterBHO to what I have below.

[ComRegisterFunction]
        public static void RegisterBHO(Type type)
        {
            // if the path doesn't exist then create it
            RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BHOKEYNAME, true);

            if (registryKey == null)
                registryKey = Registry.LocalMachine.CreateSubKey(BHOKEYNAME);

            // if the Key for this BHO doesn't exist then create it
            // NOTE: The guid comes from the Guid attribute for this class (not the one in the AssemblyInfo.cs)
            string guid = type.GUID.ToString("B");
            RegistryKey ourKey = registryKey.OpenSubKey(guid);

            if (ourKey == null)
                ourKey = registryKey.CreateSubKey(guid);

            // We only use this BHO in iexplore.exe, not explore.exe, so tell it not to load in explore.exe with the special flag (the name should not be changed)
            ourKey.SetValue("NoExplorer", 1);

            // clean up
            registryKey.Close();
            ourKey.Close();
        }

This will prevent Windows Explorer from loading it (assuming that is what you want as well). Register the .dll using regasm.exe and then open IE. There you have it.

Remember, you can also use Visual Studios debugging facilities. You just have to set your breakpoints, build, open IE, attach to the process (VS | Debug menu | Attach to Process…| look for iexplore.exe in list and click the Attach button. Now navigate or refresh in IE. The debugger should hit your breakpoint if you put it in the BeforeNavigate2 or DocumentComplete event.

If you want to find more info on this stuff I suggest searching for DWebBrowserEvents2 or BeforeNavigate2 or DocumentComplete or better yet start by checking out the links below.

Useful Links

How to attach to Browser Helper Object (BHO) with C# in two minutes
This is where I started from since it is in C#, converts to VS 2010 with no errors, and is easy to follow. I built my first BHO based on this.

Creating Custom Explorer Bars, Tool Bands, and Desk Bands
Explains the different type of add-ons

Developing IE Add-ons
Has links to lots of useful articles, sites, etc. Links to IE Protected Mode considerations. Links to how to write Browser Helper Objects (BHO).

Building Browser Helper Objects with Visual Studio 2005
Good article that seems to apply to VS 2010 as well. Good intro.

15 Seconds: Build a Managed BHO and Plug into the Browser
Good tutorial on Browser Helper Objects (BHO).

Tuesday, February 1, 2011

Solution for Can’t disable/enable add-on in Internet Explorer

If you can’t enable or disable any add-ons in Internet Explorer then it is likely that there is a group policy that is preventing you from doing it. Like most group policies they can be temporarily overwritten by modifying the registry key. You can copy and paste the text in blue into a text file and give it the .reg exension. Now when you open it, it will modify the registry for you. Below the setting is set to 0 which means that you CAN enable or disable add-ons in Internet Explorer. Set it to 1 to prevent yourself from doing it. NOTE: HKLM is for all users, however if you go to the same path, but for HKCU the change will only affect you unless there is a value in HKLM which will then override the user value (I think).

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Internet Explorer\Restrictions]
"NoExtensionManagement"=dword:00000000