InternetException

About coding and whatnot.

Using Matlab from C# application.

clock January 20, 2013 11:25 by author n.podbielski

While writing an application for my Masters degree diploma, I wrote a simple application that was using COM Matlab server. I have found it hard to use it mainly due to lack of documentation, which is really basic with only few code examples for C#. I guess writing programs that use Matlab for calculating is not encouraged by MathWorks, you would became competition that way Smile. Nonetheless, I accomplished why I was required to do, so I decided to share this with the rest of the world.

Important: I was using R2010a version of Matlab. I realize that there is a newer version. But I had only this version at my disposal. Since interface for communicating with Matlab server is dependent on installed Matlab version and registry entries, it may have been different from yours. But I suspect not too much. I also tried with 7.1 and (if I remember correctly) it required only to swap reference in Visual Studio. But again... it was only a test so there might be other problems that I am not aware of.

Let's start with a simple console application. Let's call it MatlabTest. First, we will add DLL reference with COM interface. Click RMB on project and choose [Add Reference] option. In new window, click COM tab. In search text box, write 'Matlab'. Then choose "Matlab Application (Version 7.10) Type Library".

You should get a new reference like below:

Great. Now we should test if it is working. In order to use it, we should create our Matlab server from C# application. To do that, we can add code to our main program:

var activationContext = Type.GetTypeFromProgID("matlab.application.single");
var matlab = (MLApp.MLApp)Activator.CreateInstance(activationContext);
Console.WriteLine(matlab.Execute("1+2"));
Console.ReadKey();

This code will create a single Matlab COM server through Activator class. Program Id "matlab.application.single" means single Matlab COM server for our application. When it will try to create another Matlab, it will just return a reference to the same object. Contrary to that, we could use "matlab.application" which will create another instance of Matlab anytime Activator.CreateIntance method will be executed. In more complex applications or for web applications or other programs which run for a long time, it may create big memory leaks since 1 instance costs around 220 Mb (on 64 bit Windows 7 and Matlab R2010a).

After creating Matlab program, execute a simple sum of 2 integers, just for testing communication - we don't need anything more sophisticated. It should return also a simple string in console:

It's really simple and more importantly, it works! Smile

This way, we can send and receive string messages with MATLAB only. It's not very useful. Also, there is one way to find out if our statement had errors. It will have 'error' string in response.

Let's try to run something like this: '1*', which will result in error:

So to check our command had errors, we have to check if output string has "??? Error" in it.

To send some parameters along with our command, we have to use one of 'Put*' methods. Best is one called PutWorkspaceData. It takes three parameters. First is the desired name of our new Matlab variable. Two others are much more tricky. To set variable correctly (so you could reference it in command), you must use global workspace. But it is called? This one took much more time than I would want. It is not mentioned in the documentation of this method. If I remember it right, I found it in some code example and it should be only "base". In the end, I created in my application another method that encapsulated PutWorkspaceData and forgot about it Smile. The third parameter is the value of our variable. It should be simple. Let's change our code to:

matlab.PutWorkspaceData("a", "base", 2);
Console.WriteLine(matlab.Execute("a*a"));

The result will be as shown below:

But it is just int. What about more complicated structures? How about multiplication of two vectors? Matlab is using .NET type double to send and receive information with our application. Again, I did not find it anywhere in the documentation, but rather reverse engineered this from data returned from Matlab. So let us try to send 2 arrays of doubles. and multiply them in Matlab. First will be named 'a' and second 'b'. Matlab command will be "a'*b". Transposition will give us a nice matrix instead for a single number.

matlab.PutWorkspaceData("a", "base", new[]{2d,3d,1d});
matlab.PutWorkspaceData("b", "base", new[]{4d,3d,2d});
Console.WriteLine(matlab.Execute("a'*b"));

And in return we will get:

Next step will be to return this output to our console app. To do that, we can use GetWorkspaceData that works similar to PutWorkspaceData or... we can use GetVariable method. This one returns dynamic so our application needs to run on .NET 4. It takes two parameters - name of variable we want to return from Matlab and again name of workspace. You really should save this string as const somewhere Smile. Change our code to:

matlab.PutWorkspaceData("a", "base", new[]{2d,3d,1d});
matlab.PutWorkspaceData("b", "base", new[]{4d,3d,2d});
Console.WriteLine(matlab.Execute("c=a'*b"));
var c = matlab.GetVariable("c", "base");

After that, in our console app, we will have variable c and it will be a two dimensional array of doubles. To show values of this array in console, we can just iterate it with a simple foreach loop. But instead of that, we will iterate two of the dimensions. This will give us information about values and dimensions of this matrix.

for (var i = 0; i < c.GetLength(0); i++)
{
   for (var j = 0; j < c.GetLength(1); j++)
        Console.Write(c.GetValue(i, j) + " ");
   Console.WriteLine();
}

Ok.That was matrix. How about vectors? Luckily, vectors are for Matlab just a special case of matrix so it will spit out two dimensional array also. More complex is the case of empty matrix. No, it is not null. It would be too easy. Instead, it is a special type Missing. I guess it has some logic behind. Null would indicate that variable will have no value at all or this is not defined. But we have an empty matrix, so this is not defined nor is this a lack of value. So why not just array with zero values in it? No idea.

Let's try to run code like below to test it:

Console.WriteLine(matlab.Execute("c=a'*b"));
Console.WriteLine(matlab.Execute("d=[]"));
var c = matlab.GetVariable("c", "base");
var d = matlab.GetVariable("d", "base");
for (var i = 0; i < d.GetLength(0); i++)
{
   for (var j = 0; j < d.GetLength(1); j++)
      Console.Write(d.GetValue(i, j) + " ");
   Console.WriteLine();
}

Running those commands in Matlab will work just fine. Instead of that, error will be thrown on first for loop:

Not very nice. To prevent this error, the application will have to check if dynamic type returned from matlab is in fact empty (Missing). Not very clean it is better to wrap this in other method that will perform this check for us whenever we want to get our data from Matlab. In my project, I ended up writing few methods for returning vectors, matrices, numbers, strings, etc. Vector one looked like this:

public static Vector GetVector(this MLApp.MLApp matlabComObject, string variabla_name)
{
    var dynamicVariable = matlabComObject.GetBaseWorkSpaceVariable(variabla_name);
    var dataList = new Vector();

    if (TypeChecker.IsVector(dynamicVariable))
    {
        dataList = Vector.DynamicToVector(dynamicVariable);
    }
    else if (TypeChecker.IsNumber(dynamicVariable))
    {
        dataList.Add(dynamicVariable);
    }
    else if (TypeChecker.IsEmptyMatrix(dynamicVariable))
    {
        //do nothing empty vector or matrix ([0x0] or [1x0])
    }
    else throw new Exception(string.Format(
      "Type of dynamic variable ({0}) is not supported!", dynamicVariable.GetType()));
    return dataList;
}

TypeCheker checks for type of dynamic. It's pretty straightforward. For our Missing type, it's just one line:

public static bool IsEmptyMatrix(object dynamicVariable)
{ return dynamicVariable.GetType() == typeof(Missing); }

After checking type of dynamic, we can just cast it to another type to take advantage of static properties of language. Why use dynamic at all? First, I think that ref and out method parameters are messy and second: I prefer:

var d = matlab.GetVariable("d", "base");

from:

object e;
matlab.GetWorkspaceData("d", "base", out e);

It is only 1 line. And since object you have to create first and then cast it also, don't bother and just use dynamic. But I guess it is just what you will like better.

Strings are much more friendly and there are just string. Or null. Smile

Now we know how to put and get data from Matlab. How to execute commands and check them for errors.

If you executed any of these examples, you probably took notice of a very simple Matlab window which had opened during the life of your console app. If you terminate it by disabling debugging or it will close due to error, Matlab window will remain opened. If not, it will close nicely with console window. But still, it is a huge memory leak risk if not maintained properly. To that, I recommend creating some special class that will create an instance or instances of Matlab. It should track one of the created instances and in case anything bad happens (but dynamic variable cast is probability Smile), it will close all instances prior to application exit. Tracking should be employed through WeakReference class, so whenever Garbage Collector would want to destroy Matlab instance, it should not be stopped by our tracking class. To destroy COM instance, we can use method Marshal.FinalReleaseComObject. So with weak reference code for that will look like this:

public static void Release(WeakReference instance)
{
    if (instance.IsAlive)
    {
        Marshal.FinalReleaseComObject(instance.Target);
    }
}

Method Quit of matlab server instance does not close it immediately and the code above will.

If you want to hide that popup Matlab window, you can set this in its instance:

matlab.Visible = 0;

This way, it will fade away and run as service.

This is the most basic information about Matlab in C#, but it will get you started. So happy coding! Smile



Server controls in separete assembly part 2

clock December 24, 2012 05:14 by author n.podbielski

Yesterday I was writing about creating server controls in separete assembly. Today I will cover more complicated example then simple "Hello World!" control. My goal was to create text box that will take handler method to run when validation event will be triggered, and when validation fail will show approriate messege. Text box with bultin validation would be nice, since you always should validate user input, right? But lets start creating our control.

First create new control named TextBoxWithValidation.ascx in our yesterday web site WebSite1 project.

 

Lets now fill it with some html code.

<span>
    <asp:TextBox runat="server" ID="tbText" OnTextChanged="tbText_TextChanged"></asp:TextBox>
    <asp:CustomValidator runat="server" ID="cvValidator" ControlToValidate="tbText" 
        OnServerValidate="cvValidator_ServerValidation"
        EnableClientScript="false"
        ErrorMessage="Dummy text error message" 
        Display="None" ValidateEmptyText="true">
        <%--validator must have ErrorMessage string--%>
    </asp:CustomValidator>
    <div class="ui-widget validation-error" id="divValidationContainer" runat="server"
        visible="false">
        <div class="ui-state-error ui-corner-all">
            <span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-alert"></span>
            <asp:Label ID="lValidationMessage" CssClass="validation-message" runat="server"></asp:Label>
        </div>
    </div>
</span>


This HTML is using some CSS classes as it some HTML code from jQueryUI. So it will be good if you grab newest version from http://jqueryui.com/.

 You can ofcourse use you own html for validation error message.

ASCX file contains 2 ASP.NET controls, text box and custom validator. Validator will be validating value of our text box by custom handler assigned from external page or control. We are setting ErrorMessege property with "Dummy text error message" because validator would not run validation event without it. It's some kind internal logic in .NET Framework. That's why we set it to 'dummy' to in case some um... error it would display some hint that there is something wrong with validation, and this is not validation message. Lets jump to .cs file.

 

public partial class TextBoxWithValidation : System.Web.UI.UserControl
{
    public string Text
    {
        get
        {
            return tbText.Text;
        }
        set
        {
            tbText.Text = value;
        }
    }

    public bool IsValid
    {
        get
        {
            return cvValidator.IsValid;
        }
    }
    
    public string ErrorMessage
    {
        get
        {
            return cvValidator.ErrorMessage;
        }
        set
        {
            cvValidator.ErrorMessage = value;
        }
    }

    public event ServerValidateWithMessageEventHandler ServerValidate;

    protected void cvValidator_ServerValidation(object source, ServerValidateEventArgs args)
    {
        if (ServerValidate != null && Visible)
        {
            var argsWithMessage = new ServerValidateWithMessageEventArgs(args);
            ServerValidate(source, argsWithMessage);
            argsWithMessage.ToServerValidateEventArgs(args);
            divValidationContainer.Visible = !argsWithMessage.IsValid;
            if (!argsWithMessage.IsValid)
            {
                if (string.IsNullOrEmpty(argsWithMessage.ErrorMessage))
                {
                    lValidationMessage.Text = cvValidator.ErrorMessage;
                }
                else
                {
                    lValidationMessage.Text = argsWithMessage.ErrorMessage;
                }
            }
            else
            {
                lValidationMessage.Text = "";
            }
        }
    }
}


First we are making proxy of properties IsValid and ErrorMessage, and also of property Text of TextBox. They will be handy in future Smile

Next are public event for text box value Validation ServerValidate and protected function that will run this event cvValidator_ServerValidation. Argument of this method args is defined as below:

public delegate void ServerValidateWithMessageEventHandler
            (object source, ServerValidateWithMessageEventArgs args);

public class ServerValidateWithMessageEventArgs : ServerValidateEventArgs
{

    public ServerValidateWithMessageEventArgs(ServerValidateEventArgs args)
        : base(args.Value, args.IsValid)
    { }

    public string ErrorMessage { get; set; }

    internal void ToServerValidateEventArgs(ServerValidateEventArgs args)
    {
        args.IsValid = IsValid;
    }
}

In this argument in parent control or page we can set ErrorMessege property and will obtain IsValid property value after event execution will complete. In control method cvValidator_ServerValidation we will also show or hide our custom validation message depending if value of text box is valid or not.

Let's try it out. We will publish WebControl project, and add reference to this new control by adding App_Web_textboxwithvalidation.ascx.cdcab7d2.dll file. Next add another line to web.config like yesterday:

<add tagPrefix="WebControls" namespace="ASP" assembly="App_Web_textboxwithvalidation.ascx.cdcab7d2" />


Now we can add our new control to page:

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <link href="JqueryUI/css/redmond/jquery-ui.custom.min.css" rel="stylesheet" type="text/css" />
    <link href="jQueryUI.Validation.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <WebControls:helloworld_ascx runat="server" />
        <WebControls:textboxwithvalidation_ascx ID="test" runat="server" ErrorMessage="testMessage" OnServerValidate="test_ServerValidate" />
        <br />
        <asp:Button runat="server" Text="Validate" />
    </div>
    </form>
</body>
</html>

with some button to trigger postback and some method to validate:

        protected void test_ServerValidate(object source, ServerValidateWithMessageEventArgs args)
        {
            if (args.Value.Length > 5)
            {
                args.ErrorMessage = "Value is too long!";
args.IsValid = false; } }

 

As for styles first is standard jQueryUI redmond theme css file and second is custom css for jQueryUI theme which places validation message right from text box as popup with nice eye-candy effects Smile:

/*validation*/
.validation-error
{
    display: inline-block;
    position: absolute;
    z-index: 1000;
}
.validation-error .ui-icon-alert, .errorResultContainer .ui-icon-alert
{
    float: left;
    margin-right: .3em;
}
.validation-error .ui-state-error
{
    padding: 5px;
    box-shadow: 5px 5px 5px #888888;
}
.validation-error .validation-message
{
    display: none;
    position: relative;
    text-shadow: 2px 2px 2px activeborder;
}
.validation-error:hover .validation-message
{
    display: block;
}
.validation-error:hover
{
    z-index: 1001;
}
.ui-icon-alert
{
    float: none !important;
}

After running our project and clicking on button when value of text box is longer then 5 chars we will se validation popup:

 

 

when you hover on popup you will see error description:

 

 

You can validate value for more then one constraint. Just remember to set ErrorMessage property and IsValid property to false of args parameter. That is all.



Server controls in separate assembly

clock December 22, 2012 14:52 by author n.podbielski

In my project I wanted to create text box control with bultin configurable validation. ASP.NET definition in .aspx or .ascx file would get validation function by name. But I do not wanted to create just .ascx file with text box. I could not then reuse that control in other projects and it certainly would be nice, right? Creating such server control from code is not hard, but maintability of HTML code in C# (it cannot be done other way) is not good. It's pain really. Why Microsoft would create way to automatically create C# code from .ascx, .aspx files is mistery for me.

But what we can do get around this problem? Only solution I could find is using WebSite project type. You creates such controls or pages in that project and then after publish with specific options you can obtain .dll files for every control and page in that project. You can add web site to your solution by clicking right mouse button on solution and then Add>New Web Site.

After that in your new project add new control file: HelloWorld.ascx

Great. Now in control Add "Hello World!" text.

Now we must build our WebSite. Right click on your web site project and chose "Publish Web Site" option. Choose options like on screen:

After click on "ok" button, when Publish ends, in destination path in "bin" folder, we will see some files:

This strangely named file "App_Web_helloworld.ascx.cdcab7d2.dll" is our compiled HelloWorld control. Great! Now we just have to add reference to whis assembly in our Web Application project. This can be done by reference menu like with every other .dll file. After adding it we just have to configure project to use control from that asembly. That is tricky part. Despite the fact that we did not add namespace to our control, website project did that for us. This namespace is called ASP. So to use this control in our web application project we need to insert this configuration into web.config file:

<configuration>
  <system.web>
    <pages>
      <controls>
        <add tagPrefix="WebControls" namespace="ASP" assembly="App_Web_helloworld.ascx.cdcab7d2" />
      </controls>
    </pages>
  </system.web>
</configuration>


Now we can use our new control in page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <WebControls:helloworld_ascx runat="server" />
    </div>
    </form>
</body>
</html>

That is all. Tomorrow I'll cover topic of making more complicated controls.

Smile



Handling Ajax errors in ASP.NET

clock December 22, 2012 09:58 by author n.podbielski

Yesterday I wrote about issue with Ajax postbacks in application I am working currently. Problem was with buttons that was triggering UpdatePanels to update asynchronously. After adding loading indicator I wanted to add error handling at client side.

As loading was handled by PageRequestManager events I was trying to achieve errors the same way. At first I created some html to show when error happens:

<div id="errorDialog" class="hidden">
    <div class="ui-widget center height100per width100per">
        <div class="ui-state-error ui-corner-all" style="padding: 0 .7em;">
            <p>
                <span class="ui-icon ui-icon-alert" style="float: left; margin-right: .3em;"></span>
                <strong>Error:</strong>
                <br />
                <span id="errorDesc"></span></p>
        </div>
    </div>
</div>

It creates Alert container from jQueryUI theme as you can see here http://jqueryui.com/themeroller/. For me it's looks like this:

 

Styles are mostly from this library. Mine classes have meaningful names and are defined:

.width100per
{
    width:100%;
}
.height100per
{
    height:100%;
}


Folks at Microsoft does not added special event for handling errors in PageRequestManager, but args argument of event endRequesthandler can tell as if something bad happened inside our application:

pageManager.add_endRequest(function (sender, args) {
        if (args.get_error() != undefined) {
                alert("Ouch!");
alert(args.get_error().message);
  } });


Now we have to just add some logic to show error message inside our error container:

pageManager.add_endRequest(function (sender, args) {
        if (args.get_error() != undefined) {
            var errorMessage = args.get_error().message;
            args.set_errorHandled(true);
            jQuery('#errorDesc').html(htmlEncode(errorMessage).replace(":", "<br />"));
            jQuery('#errorDialog').dialog({
                width: 600,
                height: 300
            });
        }
        function htmlEncode(value) {
            return jQuery('<div/>').text(value).html();
        }
    });



htmlEncode function replaces special HTML charachters like < or > with HTML entities. It's works by creating in-memory-only div element, and then setting some HTML as text and getting this as HTML. Simple as that. I added replacing : with HTML next line to show error description from C# in below summary of exception. After that dialog is opening to show to user that something bad happens.

Dialog is much bigger then it needs to be but I think that user must know that it's something serious and bigger message helps with that Smile

That's all!



Global UpdatePanel loading indicator in ASP.NET

clock December 21, 2012 10:48 by author n.podbielski

When I started working on application I am working right now, one of first things I noticed, that was not entirely wrong but was inconvenient: when user clicked on some button that triggers update panel you was not entirely sure it worked or not. Why? Because of three things:

1. I don't know who was developing application before me but sufice to say this person was not thorough with work :) So in many places code worked like Ash in Pokemon (Catch'em all!) with big try catch in whole methods. When exception happend it was not propagated to browser. Maybe it worked, or failed or is still working, you would never known.

2. Code was not optimized. It was slow actually. When it should just add simple entity to DB it was running several seconds. User was not aware of that.

3. Use of UpdatePanels with asynchronous postback and without loading indicator.

 

Changing code to get rid of all 'pokemon error catching' it was work for several days. Not solution I was looking for. It had to be done but not in that moment. Same thing with code optimization.

So I had to add some loading gif. But how to add it to all UpdatePanels? In ASP.NET there is UpdateProgress control but it is associated with single UpdatePanel and useless in that case.

What about ASP.NET Ajax API? PageRequestManager have several events for handling such things.

 

In that particular case it have one usefull event: add_endRequest.

 

Enough with rumbling! Let's jump to the code! :)

 

First we have to create some html code to show  when loading is pending. I used this great site to obtain simple .gif image to show: http://www.ajaxload.info/

With generated image i created HTML like this:

<div id="loadDialog" class="hidden">
    <div class="center height100per width100per">
        <img class="loadingImg height100per" src="<%=Page.ResolveUrl("~/image/loadingCircle.gif") %>"
            alt="Loading" />
    </div>
</div>



And some CSS to style this:

/*miscelanous*/
.hidden
{
    display:none;
}
.center
{
    text-align:center;
    margin:auto;
}
.width100per
{
    width:100%;
}
.height100per
{
    height:100%;
}
/*load dialog*/
div.loadDialog img.loadingImg
{
    height: 100%;
}


Wait, it's not there yet. This is just html, initially hidden. To show this I used jQueryUI modal dialog. This will prevent users clicking here and there. They might broke something, you know. Here is JS snippet I used:

    var dialogSelector = '#loadDialog';
    jQuery(function () {
        jQuery(dialogSelector)
                    .removeClass("hidden")
                    .dialog(
                        {
                            modal: true,
                            draggable: false,
                            closeOnEscape: false,
                            resizable: false,
                            width: 10,
                            height: 100
                        }).parent().css(
                        {
                            position: 'fixed'
                        });
        jQuery(dialogSelector).parent().find('.ui-dialog-titlebar').hide();
        jQuery(dialogSelector).dialog('close');
    });

    var pageManager = Sys.WebForms.PageRequestManager.getInstance();
    pageManager.add_beginRequest(function () {
        loadTimeOut = setTimeout(function () {
            jQuery(dialogSelector).dialog();
        }, 2000);
    });
    pageManager.add_endRequest(function () {
        if (loadTimeOut) {
            clearTimeout(loadTimeOut);
        }
        jQuery(dialogSelector).dialog('close');
    });


This function will run on load, show our loading dialog and instantly hide it again. This way it will show dialog without second initialization when it's gonna be really needed. First initialization is somewhat complicated so I decided to do it once. To show dialog after that I just call:

jQuery(dialogSelector).dialog();



Now let's explain what is happening in initialization. jQueryUI have solution for hiding html elements, so first thing I do is to remove my 'hidden' class. Then I create dialog with modal option, disabled dragging and resizing, closing on [ESC] key press. This will disable any user interaction with dialog itself and whole page.
Great. Width and height options are to make it as small possible (it will scale to image size anyway). After that setting position as fixed will assure that our dialog is always on center of the page. jQueryUI creates some nifty title bar for dialogs we don't want, so line:

jQuery(dialogSelector).parent().find('.ui-dialog-titlebar').hide();



will make it go away.
After that dialog is closed.
I decided that is also good thing to not flash with this dialog user every time something, even smallest thing is updating. User attention span is about 2 seconds. After that they start wondering and clicking again. So 2 seconds is good time to show dialog. For that is timeout:

    var pageManager = Sys.WebForms.PageRequestManager.getInstance();
    pageManager.add_beginRequest(function () {
        loadTimeOut = setTimeout(function () {
            jQuery(dialogSelector).dialog();
        }, 2000);
    });

 And to handle end request event:

 

    pageManager.add_endRequest(function () {
        if (loadTimeOut) {
            clearTimeout(loadTimeOut);
        }
        jQuery(dialogSelector).dialog('close');
    });


which will clear timeout of request with completion time < 2s and then closes dialog it time was more then 2 seconds. That's all. In my case it give nice looking dialog like this:




Better algorithm for finding UpdatePanel that will be updated during page request.

clock December 13, 2012 15:50 by author n.podbielski

Other day I was experimenting with finding which UpdatePanel will be updated during page post back.

I found out that my solution was not working correctly for complex triggers, like user controls with custom events, which will trigger async postbacks and update of panel.

Or for grids with buttons. It was big issue. Also it was not pointing to correct UpdatePanel if name of control was not entirely unique (for example when you have multiple same custom controls on page). It would return first panel, even if it wasn't updating.

So here is updated code:

 

      

        public static UpdatePanel FindAsyncPostBackUpdatePanel(this Page page)
        {
            var scriptManager = ScriptManager.GetCurrent(page);
            var pageRequestMngr = scriptManager.GetNonPublicProperty<object>("PageRequestManager");
            var updatePanels = pageRequestMngr.GetNonPublicField<List<UpdatePanel>>("_allUpdatePanels");
            var source = page.FindControl(scriptManager.AsyncPostBackSourceElementID);
            UpdatePanel parentUp = null;
            //check if is child of update parent with children as triggers
            Control parent = source.Parent;
            while (parent != null && parentUp == null)
            {
                parent = parent.Parent;
                parentUp = parent as UpdatePanel;
                if (parentUp != null && (CheckIfPostbackSourceInTriggers(source, parentUp) || parentUp.ChildrenAsTriggers
                    || (parentUp.IsInPartialRendering || parentUp.GetNonPublicProperty<bool>("RequiresUpdate"))))
                {
                    break;
                }
                parentUp = null;
            }
            if (parentUp != null) return parentUp;
            foreach (var up in updatePanels)
            {
                if (CheckIfPostbackSourceInTriggers(source, up))
                    return up;
            }
            return null;
        }

        private static bool CheckIfPostbackSourceInTriggers(Control source, UpdatePanel up)
        {
            foreach (var trigger in up.Triggers)
            {
                var t = trigger as AsyncPostBackTrigger;
                if (t == null)
                {
                    continue;
                }
                if (t.GetNonPublicField<Control>("_associatedControl").UniqueID == source.UniqueID)
                {
                    return true;
                }
            }
            return false;
        }

 

What have changed?

1. I added code for traversing parent controls of our source control. Most of the time control that is causing post back is children of UpdatePanel. Such a loop is much quicker then finding out all of UpdatePanels, and checking its triggers.

Also if grid with some grid-specific event caused UpdatePanel to update, this grid probably will be child of UpdatePanel and so will be button from that grid. Still it's not ideal. If you have grid with some entities (customers for example), and you want to clicking at some customer will open it's edit view in UpdatePanel in some other part of page. Source and UpdatePanel are not in child-parent relation.

If source is child of UpdatePanel method will check if ChildrenAsTriggers is true - panel will be updated cause it's triggered by child.

If IsInPartialRendering flag and RequiresUpdate, after some test I can say that that this flags indicates if UpdatePanel will be updated. Interesting thing that first flag was not true even if given UpdatePanel was indeed updating. I don't know why. But second flag non-public property was true in those situations.

2. Checking only for control Id was not reliable since it doesn't must be unique for page. That's why I am checking for unique id, of non-public field with trigger control instance and source unique id. That have to give correct answer only for one control, but is much slower since is using reflection.

 

That's it for now but I fill that I will have to revise that code once again soonSmile



Display message on client from anywhere in code with ASP.NET

clock December 10, 2012 09:20 by author n.podbielski

When I was working with WinForms application in previous work I have found one of most useful feature, ability to show some message to the client. For example user cannot edit some entity in particular time (it is being edited by someone else) or should change pasword because it will exprire in x days. I wanted to do something similar in my web application.

To do that I started with creating control with html code of new message window. Sure you can use just JS alert() function, but I find this really annoying. So instead I used jQuery UI dialog.

<script language="javascript" type="text/javascript">
    function showMessage(message) {
        if (typeof (message) !== "undefined" && message) {
            jQuery('#messageContent').html(message);
            jQuery('#messageDialog').dialog({
                width: 600,
                height: 300
            });
        }
    };
</script>
<div id="messageDialog" class="hidden">
    <div class="ui-widget center height100per width100per">
        <div style="padding: 0 .7em;" class="ui-state-highlight ui-corner-all">
            <p>
                <span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-info"></span>
                <strong>Information:</strong> <span id="messageContent"></span>
            </p>
        </div>
    </div>
</div>

I decided to put this control called WUC_MessageDoalog in Site.Master file. That way JS function showMessage will be available for all pages using master page (in my application that was all desired pages).If it is not enaough it is possible to inject this control and JS code into page whenever it will be needed, but it was not necessary in my case.

Now we can execute showMessage function when we need to show some message. To do that we have to use Page.RegisterStartupScript method. 

Page.ClientScript.RegisterStartupScript(page.GetType(), key, string.Format("<script type='text/javascript'>{0}</script>", script));

To abstract this code an made it available in whole application I made extension method of Page type.

public static void AddStartupScripts(this Page page, string key, string script)
{
    if (!page.ClientScript.IsStartupScriptRegistered(key))
    {
        page.ClientScript.RegisterStartupScript(page.GetType(), key,
            string.Format("<script type='text/javascript'>{0}</script>", script));
    }
}

 

After using this function it will render <script type="text/javascript"> tag with our desired code. To execute showMessage we have to insert JS code to our AddStartupScripts method:

jQuery().ready(function () {
    {
        showMessage("I am a message!");
    }
});

I made another extension method from this.

public static void AddClientReadyScript(this Page page, string key, string script)
{
    page.AddStartupScripts(key, string.Format(
        @"jQuery().ready(function () {{
            {0}
        }});", script));
}

But still it will only work for full HTTP Postback. How to make this work with AJAX? Things are more trickier from here. To execute JS code after UpdatePanel AJAX PostBack, we have to use method ScriptManager.RegisterClientScriptBlock.

I encapsulated this in similar way likeAddStartupScripts method.

public static void AddUpdateScript(this UpdatePanel panel, string key, string script)
{
    if (!panel.Page.ClientScript.IsClientScriptBlockRegistered(key))
    {
        ScriptManager.RegisterClientScriptBlock(
            panel, typeof(UpdatePanel), key, script, true);
    }
}

JS code injected into page like this does not need further encapsulating so we leave it like that. But we still have to know which UpdatePanel will be updated to inject JS into it. How to do that? Sadly there is no easy solution. After some Google reasearch, and few hours I managed to create another extension method (yes I like them a lot!):

 

public static UpdatePanel FindAsyncPostBackUpdatePanel(this Page page)
{
    var scriptManager = ScriptManager.GetCurrent(page);
    var pageRequestMngr = scriptManager.GetNonPublicProperty<object>("PageRequestManager");
    var updatePanels = pageRequestMngr.GetNonPublicField<List<UpdatePanel>>("_allUpdatePanels");
    var source = page.FindControl(scriptManager.AsyncPostBackSourceElementID);
    foreach (var up in updatePanels)
    {
        foreach (var trigger in up.Triggers)
        {
            var t = trigger as AsyncPostBackTrigger;
            if (t == null)
            {
                continue;
            }
            if (t.ControlID == source.ID)
            {
                return up;
            }
        }
    }
    return null;
}


If you wondering what are GetNonPublicField and GetNonPublicProperty methods do you can find about the here:
post/2012/12/09/Getting-private-field-or-property-from-object.aspx

I found this working fine for me, but still it have some obvious drawbacks:

1. It founds update panel only by its explicitly defined triggers. So it will not work for triggers that are children of update panel. Still I recomend you to not do that. Nested panels with ChildrensAsTriggers = true will cause to update, panel which is most higher in controls tree hierarchy. So biggest update panel (for example containing whole page) will update. Why even bother with nested panels in that case or even AJAX at all then?

2. It uses control id that is not unique. When you will use not unique ids for your controls (i.e. button1, textbox1), you will end up adding script to first update panel that will pop up. And it will not work. But if you writing your site like this I bet that you have bigger problems :)

3. It will not work with RegisterAsyncPostBackControl method and control outside of panel. But if it is static relation it can be placed inside of update panel triggers collection.

Anyway, with this method mostly working we can write yet another extension to Page:

public static void ShowClientMessage(this Page page, string message)
{
    if (page.Master != null)
    {
        var siteMasterDialog = page.Master.FindControl("wucMessageDialog");
        const string messageScriptKey = "clientDialogMessage";
        if (siteMasterDialog != null)
        {
            var jsCode = string.Format("showMessage('{0}');", message.Replace("'", "\\'"));
            if (page.IsPostBack && ScriptManager.GetCurrent(page).IsInAsyncPostBack)
            {
                var up = page.FindAsyncPostBackUpdatePanel();
                up.AddUpdateScript(messageScriptKey, jsCode);
            }
            else
            {
                page.AddClientReadyScript(messageScriptKey, jsCode);
            }
        }
    }
}

And finally with right tools we can abstract this further to stand alone class. If we will be using only ASP.NET Page handlers, current page instance can be obtain from HTTPContext object via Handler property:

 
public class ClientMessage
{
    public void ShowWarning(string message)
    {
        var page = ((Page)HttpContext.Current.Handler);
        page.ShowClientMessage(message);
    }
}

That is all about magic. To show message from some code in our site just call:

 new ClientMessage().ShowWarning("I am message!");

If everything is working fine you'll end up with dialog like this:

And that's all.Smile



Getting private field or property from object

clock December 9, 2012 07:26 by author n.podbielski

Yesterday I was playing with finding all UpdatePanel controls on page during generating response in ASP.NET. Since object with this information is private itself and collection of panels is private in that object, I had to write some code to extract that data. I ended up with to extension methods for Object type, for getting private field an private property. It's pretty straightforward, besides one thing: since member is private. And we don't know in witch type exactly (every type in base/descendent hierarchy have it's one private members) we have to search them all. So this is final code:

    public static class ObjectExtensions
    {
        public static TRet GetNonPublicField<TRet>(this object o, string fieldName)
        {
            var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;
            return (TRet)IterateTypesForMember(o, fieldName, bindingFlags);
        }

        public static TRet GetNonPublicProperty<TRet>(this object o, string propertyName)
        {
            var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty;
            return (TRet)IterateTypesForMember(o, propertyName, bindingFlags);
        }

        private static object IterateTypesForMember(object o, string memberName, BindingFlags bindingFlags)
        {
            Type type = o.GetType();
            MemberInfo[] memberInfo;
            do
            {
                memberInfo = type.GetMember(memberName, bindingFlags);
                if (memberInfo.Length == 0)
                {
                    type = type.BaseType;
                }
            } while (memberInfo.Length == 0 && type != null);
            var member = type.InvokeMember(memberName, bindingFlags, null, o, null);
            return member;
        }
    }