Resolving relative URL’s from JavaScript

An entry about javascript | asp.net | asp.net mvc Publication date 22. August 2009 14:50

On the server side of an ASP.NET or ASP.NET MVC application, we’re used to working with relative URL’s in the style of “~/Images/logo.png”. This makes our application safely deployable to virtual directories within IIS applications without messing up the URL’s. However, what do we do if we need the same functionality in our JavaScript?

I’m solving this by sticking the following script in my Site.Master file:

Url = function() { }

Url.prototype =
{
    _relativeRoot: '<%= ResolveUrl("~/") %>',

    resolve: function(relative) {
        var resolved = relative;
        if (relative[0] == '~') resolved = this._relativeRoot + relative.substring(2);
        return resolved;
    }
}

$Url = new Url();

Now, anywhere I need to resolve a relative url in a script, I can do this:

var logoUrl = $Url.resolve("~/Images/logo.png");

Currently rated 4.5 by 4 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

MSDN Live - Stavanger, Bergen & Trondheim Done!

An entry about asp.net | conferences Publication date 11. September 2008 15:06

I've just finished my last session at the MSDN Live event in Trondheim, after doing Stavanger last week and Bergen on Tuesday. Its been great so far, and I'm really looking forward to the final event in Oslo on the 30th of September. Rumour has it that a very special guest will be making a surprise keynote appearance, so you really don't want to miss it! ;)

For those of you that have attended my Introduction to ASP.NET sessions so far, go check out the project site at http://www.assembla.com/spaces/msdn_live_wiki, where you can download all the slides and the demo application.

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Ninject Module for ASP.NET MVC Controller Bindings

An entry about asp.net | asp.net mvc | inversion of control Publication date 25. August 2008 11:00

Setting up Ninject for use with ASP.NET MVC is dead easy; just use the integration API included in the MvcContrib project. However, registering all your controllers by hand can be tedious. Writing a custom module that automatically loads all the controllers in a given assembly is straight-forward, however:

public class ControllerModule : StandardModule
{
    private readonly Assembly _assembly;
 
    public ControllerModule(Assembly assembly)
    {
        _assembly = assembly;
    }
 
    public override void Load()
    {
        Type controllerType = typeof (IController);
 
        // find all types in the assembly that implement the IController interface
        foreach(Type type in _assembly.GetTypes())
        {
            if(controllerType.IsAssignableFrom(type))
            {
                string controllerName = type.Name;
 
                // strip the "Controller" suffix from name
                int cutIndex = controllerName.LastIndexOf("Controller");
                if(cutIndex > 0) controllerName = controllerName.Substring(0, cutIndex);
 
                // register controller binding
                Bind<IController>().To(type).Only(When.Context.Variable("controllerName").EqualTo(controllerName));
            }
        }
    }
}

And then your Global.asax will look like this:

public class GlobalApplication : HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
        // *snip* route registration
    }
 
    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
        InitializeNinject();
    }
 
    public void InitializeNinject()
    {
        NinjectKernel.Initialize(new ControllerModule(Assembly.GetExecutingAssembly()));
        ControllerBuilder.Current.SetControllerFactory(typeof(NinjectControllerFactory));
    }
}

Happy days!

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Deploying Asp.Net Sites to IIS7 from Visual Studio

An entry about asp.net | visual studio Publication date 29. March 2008 12:02

To be able to deploy Asp.Net sites to IIS7 from Visual Studio 2008 when running on Windows Vista, there's a couple of things that needs to be set up first. Aside from the fact that you need to be running Visual Studio as an administrator (either by choosing 'run as Administrator' when launching it, or by disabling the UAC), there are a few IIS6 compatibility features that needs to be installed. These can be found by going to Control Panel > Programs > Turn Windows features on or off, and ensuring that the following are checked:

Windows features

With that in place, you can go to the Web tab on the properties page for your ASP.NET project and select 'Use IIS web server' instead of the built-in development server, just like we're used to:

Asp.Net project server settings

Currently rated 3.7 by 3 people

  • Currently 3.666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Sharing Variables Between JavaScript and C#

An entry about asp.net | javascript Publication date 11. January 2008 17:53

You know, I think the most difficult part of this blog post was coming up with a descriptive title for it - it just needs more words to be explained. The story goes like this: While working on a JavaScript-heavy web application, I found myself wanting to share a set of variables between my server side C# code and the client-side JavaScript code. I wanted to be able to set a value in the JavaScript code running in the clients browser, and then later retrieve that same value on the server in the code behind of the page upon the next postback - and vice versa. It might sound a bit tricky (or maybe not?), but it proved to be quite simple - in fact, its perfect for some Friday afternoon blogging indulgence, before we get started on dinner :)

Aim First...

Whenever I decide to create a component, the first thing I do is think about how I want to use it. I find writing some mock code the perfect way to settle on an interface for the component, before even writing a line of code for it (TDD, anyone?). This way, I'm sure I'm actually making what I need, and not what I think I might need. So, let's look at some code that mimics what we want to accomplish with our component.

What I'd like to do, is to be able to drop it onto a Web Form and access it both from my JavaScript and my code behind. So, something like this:

 

<idc:ClientDictionary 
    ID="_myDictionary"
    runat="server" />

 

Having declared that in my markup, I want to be able to do this from the client-side JavaScript:

$find('_myDictionary').setValue("key", "value");

 

And then, when the form is submitted, I want to be able to retrieve that value from the server-side C#:

string value = _myDictionary.Values["key"];

 

...and Fire at Will

Okay, so hopefully you've got an idea of what I'm up to. Basically, what I want is a hidden input field - but one that can store more than one value. Instantly, I'm thinking Asp.Net Ajax - or more precisely, a Control Extender. I could write one that targets the HiddenField control, transporting my dictionary between the client and server by serializing it into the hidden input field. But while that would take care of the client-side part, I need to extend the HiddenField serverside aswell. To do that, I'll write a new component that wraps the HiddenField and the said extender control into a composite control, ready to be dropped onto a form and just work.

Without any further ado, lets look at the source code I came up with for this control:

public class ClientDictionary : CompositeControl
{
    private Dictionary<string,string> _values;
 
    /// <summary>
    /// The name of the dictionary, used for accessing the dictionary on the client using $find([name]).
    /// </summary>
    public string Name
    {
        get
        {
            EnsureChildControls();
            return _hiddenFieldExtender.BehaviorID; // we map the name to the behavior ID of the hidden field extender 
        }
        set
        {
            EnsureChildControls();
            _hiddenFieldExtender.BehaviorID = value;
        }
    }
 
    public override bool EnableViewState
    {
        get
        {
            // this control does not need view state
            return false;
        }
        set
        {
            throw new InvalidOperationException();
        }
    }
 
    /// <summary>
    /// Gets or sets the values stored in the dictionary
    /// </summary>
    public Dictionary<string, string> Values
    {
        get { return _values; }
        protected set { _values = value; }
    }
 
    protected override void OnInit(EventArgs e)
    {
        EnsureChildControls();
 
        // the hidden field contains our javascript dictionary, which we'll want to deserialize into a C# dictionary
        string serializedDictionary = this.Page.Request.Form[_field.UniqueID];
 
        if (!String.IsNullOrEmpty(serializedDictionary))
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            this.Values = serializer.Deserialize<Dictionary<string, string>>(serializedDictionary);
        }
        else
        {
            // no client-side dictionary was present, so create a new blank one
            this.Values = new Dictionary<string, string>();
        }
 
        base.OnInit(e);
    }
 
    private HiddenField _field;
    private ClientDictionaryExtender _hiddenFieldExtender;
 
    protected override void CreateChildControls()
    {
        _field = new HiddenField(); // we use the hidden field to transport our data between the server and client parts
        _field.ID = "fl";
        this.Controls.Add(_field);
 
        // the extender makes sure a client-side behavior component representing the dictionary is available
        this._hiddenFieldExtender = new ClientDictionaryExtender();
        this._hiddenFieldExtender.BehaviorID = this.Name;
        this._hiddenFieldExtender.ID = "xt";
        this._hiddenFieldExtender.TargetControlID = _field.ID;
        this.Controls.Add(this._hiddenFieldExtender);
    }
 
    protected override void OnPreRender(EventArgs e)
    {
        // its time to save the server-side dictionary into the hidden field, which will transport it to the client side component
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        _field.Value = serializer.Serialize(this.Values);
 
        base.OnPreRender(e);
    }
}

 

The comments should make the above code pretty much self-explanatory, so lets just keep rolling and dive right into the javascript code:

Type.registerNamespace('Iridescence.Web.UI');
 
Iridescence.Web.UI.ClientDictionaryBehavior = function(element)
{
    Iridescence.Web.UI.ClientDictionaryBehavior.initializeBase(this, [element]);
    this._dictionary = null;
    this._onSubmitDelegate = null;
}
 
Iridescence.Web.UI.ClientDictionaryBehavior.prototype = 
{
    initialize : function()
    {
        Iridescence.Web.UI.ClientDictionaryBehavior.callBaseMethod(this, 'initialize');
 
        this._onSubmitDelegate = Function.createDelegate(this, this._onSubmit);
        $addHandler(window, "submit", this._onSubmitDelegate);
        this._deserialize();
    },
 
    getValue : function(name)
    {
        var value = this._dictionary[name];
 
        return value;
    },
 
    setValue : function(name, value)
    {        
        this._dictionary[name] = value;
    },
 
    _onSubmit : function()
    {
        // serialize the dictionary to the hidden field    
        this.get_element().value = Sys.Serialization.JavaScriptSerializer.serialize(this._dictionary);
    },
 
    _deserialize : function()
    {
        // deserialize the dictionary from hidden field    
        this._dictionary = Sys.Serialization.JavaScriptSerializer.deserialize(this.get_element().value);          
    },
 
    clear : function()
    {
        this._dictionary = null;
        this._dictionary = new Object();
    },
 
    dispose : function()
    {
        Iridescence.Web.UI.ClientDictionaryBehavior.callBaseMethod(this, 'dispose');  
    }
}
 
Iridescence.Web.UI.ClientDictionaryBehavior.registerClass('Iridescence.Web.UI.ClientDictionaryBehavior', AjaxControlToolkit.BehaviorBase);

 

The only thing left to define is the ClientDictionaryExtender, which is dead simple:

[ClientScriptResource("Iridescence.Web.UI.ClientDictionaryBehavior", "Iridescence.Web.UI.ClientDictionaryBehavior.js")]
[TargetControlType(typeof(HiddenField))]
internal class ClientDictionaryExtender : ExtenderControlBase
{}

 

There's no server-side functionality in the extender, its job is just to hook up the JavaScript component to the hidden field. I've made it internal as well, as it makes little sense to use it without the plumbing being handled by the ClientDictionary control.

And that is all there is to it! Dropping the ClientDictionary component onto a form, I can now set and get values from its dictionary both from the client-side JavaScript and the server-side codebehind, and it will be synchronized both ways.

I've created a demo project which you can download here, which includes the working source code and a small Asp.Net application that demos the basic functionality. Enjoy!

Currently rated 5.0 by 4 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Animating an Asp.Net Ajax Control Extender

An entry about asp.net | ajax Publication date 7. December 2007 22:14

Earlier this year, I wrote a blog post describing how to develop a context menu control extender using the Asp.Net Ajax control toolkit. It was a fairly basic extender, allowing you to specify a context area and an associated control that should be displayed when the user right-clicked inside that area. In this post I'll go back and enhance the extender with support for animating the context menu.

What I want to accomplish with the end result, is the ability to write markup similar to the following:

<idc:ContextMenuExtender
    ID="_cme"
    runat="server"
    ContextMenuControlID="_contextMenu"
    TargetControlID="_contextArea">
    <Animations>
        <OnShow>
            <FadeIn Duration="0.25" />
        </OnShow>
        <OnHide>
            <FadeOut Duration="0.25" />
        </OnHide>
    </Animations>
</idc:ContextMenuExtender>

If you've used any of the control extenders in the Ajax toolkit like the PopupControlExtender or UpdatePanelAnimationExtender, I'm sure you've seen that Animations tag before. It basically allows us to set up one or more storyboards for animations that should trigger on certain events - in the example above, applying a short FadeIn animation when the context menu is shown, and a short FadeOut animation when it is hidden.

The AnimationExtenderControlBase

Originally, my ContextMenuExtender inherited from the ExtenderControlBase class. The first step towards adding support for animations, is changing this to the AnimationExtenderControlBase, which will give me all the leverage I need to easily add animation support to my extender. This new base class has a few members that I'm interested in - there's the Animations property, and the SetAnimation and GetAnimation methods. As you see from the markup above, the Animations property is the one that we'll use to set up the storyboard for animations. The cool thing about this, is that it then automatically supports all the pre-built animation types that the toolkit contains - go take a look at the documentation to learn more about animations. The only thing we need to do to make it work, is to set up the different events that we want to support animation - in our case, they're OnShow and OnHide. We do this by adding similarly named properties on our extender:

[ExtenderControlProperty]
[ClientPropertyName("onShowJson")]
[Browsable(false)]
public Animation OnShow
{
get
    {
return GetAnimation(ref _onShow, "OnShow");
}
set
    {
SetAnimation(ref _onShow, "OnShow", value);
}
}
private Animation _onHide;
[ExtenderControlProperty]
[ClientPropertyName("onHideJson")]
[Browsable(false)]
public Animation OnHide
{
get
    {
return GetAnimation(ref _onHide, "OnHide");
}
set
    {
SetAnimation(ref _onHide, "OnHide", value);
}
}

As you can see, these are decorated with the ExtenderControlProperty attribute to signal that I want the values they get set to, to be transported to the client-side component. Notice also that I've used the ClientPropertyName to change the client-side target property - I'm telling the toolkit to map the server-side property OnShow/OnHide to the client-side property onShowJson/onHideJson (or rather, the set_onShowJson/set_onHideJson and get_onShowJson/get_onHideJson methods, as JavaScript has no concept of properties).

That's it for the server-side changes - the real stuff happens client-side, after all.

Animate Me

Our client-side stuff is defined in the ContextMenuBehavior object. The first thing we do, is to add the client-side properties that we told the server-side component to map the server-side OnShow and OnHide properties to:

get_onShowJson : function() 
{
return this._onShowJson;
},
set_onShowJson : function(value) 
{
this._onShowJson = value;
},
get_onHideJson : function() 
{
return this._onHideJson;
},
set_onHideJson : function(value) 
{
this._onHideJson = value;
}

Now, recall that the Animations property on the server-side extender control was just a string - so our _onShowJson and _onHideJson fields will just end up holding string representations of the animations - incidentally in a JSON format. We can use these strings to create AjaxControlToolkit.Animation objects, and we'll do that in the initialize method of the component:

initialize : function() 
{
Iridescence.Ajax.ContextMenuBehavior.callBaseMethod(this, 'initialize');
// other stuff removed for brevity...
                
if(this._onShowJson)
{
this._onShowAnim = $AA.buildAnimation(this._onShowJson, this._menuElement);            
}
if(this._onHideJson)
{
this._onHideAnim = $AA.buildAnimation(this._onHideJson, this._menuElement);
}
}

Now, if the any animations were specified, we'll have them parsed into actual Animation objects ($AA is an alias for AjaxControlToolkit.Animation) in our component, and set to target the context menu (stored in the _menuElement field), ready to be triggered whenever the context menu is shown or hidden. To trigger them, we need to modify the showMenu and hideMenu methods of the ContextMenuBehavior prototype slightly:

showMenu : function(x,y)
{    
// set flags
    this._menuVisible = true;
this._menuJustShown = true;  
this._menuElement.style.left = x + 'px';
this._menuElement.style.top = y + 'px';    
this._menuElement.style.display = '';
if(this._onHideAnim)
{
// if the hide animation is currently running, stop it
        this._onHideAnim.stop();
}
if(this._onShowAnim)
{             
this._onShowAnim.play();
}  
}

Most of this method is the same original - the only difference is that if there's an OnShow animation specified, we start playing it, first ensuring that any OnHide animation currently playing is stopped.

hideMenu : function()    
{    
if(this._onShowAnim)
{
// if show anim is currently running, stop it
        this._onShowAnim.stop();
}
if(this._onHideAnim)
{
this._onHideAnim.play();
}     
else
    {
this._hideMenuCore();
} 
this._menuVisible = false;
}

The hideMenu method is much the same - if there's an OnHide animation we start playing it, first ensuring that any OnShow animation currently playing is stopped.

Play With Me

That was a very quick guide to adding support for animations in an Asp.Net Ajax Control Extender. You can read more about using animations over at the Asp.Net Ajax Control Toolkit website.

If you want to play around with the ContextMenuExtender, click here to download a Visual Studio 2008 solution including the source code, and an example project which shows a few usage scenarios of the extender. Feel free to use and abuse it to your hearts content :)

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Powered by BlogEngine.NET 1.4.5.0

Welcome!

My name is Fredrik Kalseth, and this is my blog - thanks for visiting! I am fortunate enough to work with what I love for a living, and this blog is essentially the biproduct of that.

I work as a senior consultant for Capgemini, and am also an active participant in the Norwegian .NET community, as an avid attendee but also as a speaker (most recently at NNUG and MSDN Live).

As a developer, I have a wide circle of interest. My primary passion is for agile, test-driven development, with focus on best practices and clean code. That said, I also love to work on the frontend, especially with web development.

On Twitter? My handle is fkalseth. On LinkedIn? I`m there too.

Disclaimer

This is a personal blog; any opinions expressed here are my own and do not necessarily reflect those of my employer. All content herein is my own original creation, and as such is protected by copyright law. Unless otherwise stated, all source code posted on this blog is freely usable under the Microsoft Permissive License.

What Readers Talk About

Comment RSS