DCSIMG
February 2008 - Posts - Doron's .NET Space

February 2008 - Posts

Overcoming IE Bug with a Custom SessionIDManager

Internet Explorer 6 has the most annoying bug in the world. When you click a window.open link in a modal dialog (opened by a call to window.showModalDialog), you sometimes lose the cookie, as the window is opened in a different process. Since that cookie usually contains your current session-id, the immediate result is that ASP.NET creates a new session for you, which rarely results in a positive outcome.

The workaround suggested in the above linked kb-article did not work, and in this specific situation I couldn't change the modal dialog into a standard window, or to the neat Ajax Control Toolkit modal dialog control we now use sometimes. Digging into the configuration options, I've discovered you can change your session state configuration to cookieless - which causes ASP.NET to add the session-id to the query-string of links instead of using the cookie. But that affects your entire web-site, and I didn't want to do that on account of one silly IE bug.

Still, this gave me the idea to pass the session-id in the query-string, and somehow use that in the server to retrieve the user's original session. This can be achieved fairly easily with a custom SessionIDManager. A SessionIDManager is responsible for creating and retrieving session-ids, and you can plug-in a custom one in your web-site's web.config. Here's the one I wrote.

    1  public class QueryStringSessionIDManager: SessionIDManager, ISessionIDManager

    2     {

    3         public new string GetSessionID(HttpContext context)

    4         {

    5             string queryStringSessionID = context.Request.QueryString["SessionID"];

    6             string originalSessionID = base.GetSessionID(context);

    7             if (!string.IsNullOrEmpty(queryStringSessionID) && originalSessionID != queryStringSessionID)

    8             {

    9                 bool redirected, cookieAdded;

   10                 base.SaveSessionID(context, queryStringSessionID, out redirected, out cookieAdded);

   11                 return queryStringSessionID;

   12             }

   13             else return originalSessionID;

   14         }

   15     }

Not much to it, really. We inherit from SessionIDManager and override GetSessionID. Well, actually, we hide it - that method is not virtual. This is why we also have to specifically implement ISessionIDManager, otherwise our method won't get called. Inside the method we look for a session-id in the query-string, and if we find one that's different from the auto-generated one, we use it.

Note that in line 10 we also save the session-id. This is required as subsequent requests might not have the SessionID query-string value. This way we "transfer" the session-id from the query-string to the cookie.

To sum it up, this is how we overcome the bug: from the modal dialog we have to add a SessionID='<%=Session.SessionID%>' to the window.open(url) link. In the opened window,  the custom session-id  manager grabs this value, saves it to the empty cookie, and uses it as the session-id instead of the new session-id that was generated by ASP.NET. The user can continue his work, he won't notice that anything happened.

Oh, and I almost forgot, this is how you configure your SessionIDManager. Put this in the <system.web> section of your web.config:

<sessionState sessionIDManagerType="CustomSession.QueryStringSessionIDManager"/>

And that's the entire story.

Posted by dorony | 6 comment(s)
תגים:

Interesting Behavior with the New Modifier and Interfaces

Consider the following code. What will be the result of calling Test.TestInterface()?

    public interface IInterface

    {

        void DoSomething();

    }

 

    public class Father : IInterface

    {

 

        public void DoSomething()

        {

            Console.WriteLine("Father Called");

        }

 

    }

 

    public class Son: Father

    {

        public new void DoSomething()

        {

            Console.WriteLine("Son Called");

        }

    }

 

    public class Test

    {

        public void TestInterface()

        {

            IInterface tester = new Son();

            tester.DoSomething();

        }

    }

Note that Father is implementing the interface, but the son is hiding the interface method with the new modifier. Logic dictates (well, at least my logic did), that when you access the son through the interface, the son's method will be called and not the father's. After all, why should it matter who in my hierarchy implemented the Interface?

Well, apparently it does matter, and this will print "Father Called". If we change Son to implement the interface by itself, i.e.

    public class Son: Father, IInterface

    {

        public new void DoSomething()

        {

            Console.WriteLine("Son Called");

        }

    }

Running the test will now print "Son Called". Seems like the method of the last object in the hierarchy that explicitly states that it is implementing the Interface, gets called. Since "DoSomething" was not virtual, and the son hides it and not overrides it, the method that gets called in the first example is the Father's. And yes, I discovered this the hard way.

Posted by dorony | 1 comment(s)
תגים:

Introducing ArcObjectFactory: Creating ArcObjects in a Type-Safe Manner

* The following is a great work by a friend of mine - Yoav Michaeli, assisted by Shani. Yoav wrote about it in his Hebrew blog, but never posted the code, so I asked for his permission to bring this to my blog.

The following is Yoav's attempt to solve two problems:

1. Creating ArcObjects in ArcGIS Server.

It is very annoying to create ArcObjects when writing ArcGIS Server Local code. i.e.

IPoint point = myServerContext.CreateObject(“esriGeometry.Point”) as IPoint;

This is not type-safe code, and does not lend itself well to refactoring. Also, many beginners with ArcObjects forget to use this syntax, and use "new" instead, which obviously doesn't work. The outcome is a lot of wasted time.

2. Converting between the ArcGIS Server code to client code, and vice versa.

When working with ArcMap or ArcEngine, you will create your objects in the standard way, i.e.

IPoint point = new PointClass();

But if you now decide to use this code over ArcGIS Server, you will have to manually change all your creation code to work against an IServerContext.

ArcObjectFactory

Yoav has solved this problem by introducing ArcObjectFactory, which confronts these issues with some (very simple) reflection magic.

You will use it like this:

 

IArcObjectFactory factory = new AgsArcObjectFactory(myServerContext);
IPoint point
= factory.CreateObject<Point>();

Now, if you want to change your code to work on the client-side, you will just have to change the first line:

 

IArcObjectFactory factory = new ClientArcObjectFactory();

Of course, this is just an example. In real life you might want your class to expose an IArcObjectFactory property, and inject the actual factory via a constructor, or an IoC container such as Windsor. This way, the exact same code can be deployed in several enviroments with no code change at all.

Also, this approach makes writing unit-tests with mocks a lot easier. At my workplace, any code that uses ArcObjects works with an ArcObjectFactory.

The full code for ArcObjectFactory can be found here. Yoav - thanks again, and good luck in your new place!

Posted by dorony | with no comments
תגים:

Replacing the Web ADF - Your Help is Needed

Following my recent bitching about the ADF, James Fee quoted me on his blog. The explosion of comments to that post made me feel all warm inside. I realized I'm not the only one who is very disappointed with the ArcGIS Server ADF, but a lot of other people are sharing the same feelings (also, this is definitely the most impact a blog post of mine has ever had).

Anyway, Dave Bouwman decided to do something about this, and he is forming a sort of Alt-ESRI movement, whose first mission should be to replace the Web ADF. I couldn't support this cause more, and I call everyone who's interested in creating web applications with ESRI tools to participate (by contacting him).

Currently my problem with developing ESRI stuff at home, is that I don't have an EDN license for my home computer. I will try to work something out, however.

Posted by dorony | 2 comment(s)
תגים: