Amazon.com Widgets All posts by williarob

WilliaBlog.Net

I dream in code

About the author

Robert Williams is an internet application developer for the Salem Web Network.
E-mail me Send mail
Go Daddy Deal of the Week: 30% off your order at GoDaddy.com! Offer expires 11/6/12

Recent comments

Archive

Authors

Tags

Code Project Associate Logo

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.


Visio files not opening in Internet Explorer

Recently, a colleague sent me a Visio file and informed me that I should be able to view it in IE. So I double clicked on it and sure enough, IE opened and warned me that "To Help protect your security, Internet Explorer has restricted this webpage from running scripts or ActiveX controls that could access your computer. Click here for options." so I did and I clicked on "Allow blocked content".

Instead of seeing the document, I was presented with a small red x, like that of a broken image. Undaunted, I thought that perhaps there is a Visio Viewer, rather like the Word and Powerpoint Viewers you can download, that would let me view Visio files, but not create them. Sure enough I found the Visio 2007 Viewer on Microsoft's site, downloaded it and installed it.

.vsd files were still associated with IE, and the results were the same. So I tracked down the Visio Viewer application in C:\Program Files (x86)\Microsoft Office\Office12; and double clicked it. "This Program can only run from within another program." Great. So, I checked the security settings in IE, and went to Manage Add-ons to see if the Visio Viewer was disabled or blocked, but it didn't even appear in the list.

With a little help from Google, I discovered that the solution was to uninstall a security update "Cumulative Security Update for ActiveX Killbits for Windows 'Your Version of Windows Here' (KB973525)"

The link to the update is here:  http://go.microsoft.com/fwlink/?LinkId=158202.  It appears that Microsoft in it's infinite wisdom accidentally put the Visio Viewer's CLSID in the kill list. Uninstalling this update, resolved the issue and I can now open Visio documents in IE.


Categories: Office
Posted by Williarob on Thursday, November 19, 2009 1:22 PM
Permalink | Comments (5) | Post RSSRSS comment feed

How to get the length (duration) of a media File in C# on Windows 7

If you have ever looked at a media file (audio or video) in the explorer window on a Windows 7 PC, you may have noticed that it displays additional information about that media file that previous versions of Windows didn't seem to have access to, for example the length/duration of a Quicktime Movie Clip:

 

Even right clicking the file and choosing Properties > Details does not give me this information on my Vista Ultimate PC. Of course, now that Windows has the ability to fetch this information, so do we as developers, through the Windows API (The DLL to Import by the way is "propsys.dll"):

        internal enum PROPDESC_RELATIVEDESCRIPTION_TYPE

        {

            PDRDT_GENERAL,

            PDRDT_DATE,

            PDRDT_SIZE,

            PDRDT_COUNT,

            PDRDT_REVISION,

            PDRDT_LENGTH,

            PDRDT_DURATION,

            PDRDT_SPEED,

            PDRDT_RATE,

            PDRDT_RATING,

            PDRDT_PRIORITY

        }

 

 

        [DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true)]

        internal static extern int PSGetNameFromPropertyKey(

            ref PropertyKey propkey,

            [Out, MarshalAs(UnmanagedType.LPWStr)] out string ppszCanonicalName

        );

 

        [DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true)]

        internal static extern HRESULT PSGetPropertyDescription(

            ref PropertyKey propkey,

            ref Guid riid,

            [Out, MarshalAs(UnmanagedType.Interface)] out IPropertyDescription ppv

        );

 

        [DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true)]

        internal static extern int PSGetPropertyKeyFromName(

            [In, MarshalAs(UnmanagedType.LPWStr)] string pszCanonicalName,

            out PropertyKey propkey

        );

However, before you rush off to play with these, you may be interested to know that Microsoft has created a great Library that showcases this and many of the other new API features of Windows 7. It's called the WindowsAPICodePack and you can get it here.

If you open the WindowsAPICodePack Solution and compile the Shell Project, it creates a nice wrapper around all the neat new system properties available through propsys.dll. Adding a reference to WindowsAPICodePack.dll and WindowsAPICodePack.Shell.dll in a console application will allow you to get the duration of just about any media file that Windows recognizes. (Of course the more codec packs you install, the more types it will recognize, I recommend The Combined Community Codec Pack to maximize your range of playable files.)

Here is a simple example showing how to get the duration of a media file in C# using this library:

namespace ConsoleApplication1

{

    using System;

 

    using Microsoft.WindowsAPICodePack.Shell;

 

    class Program

    {

        static void Main(string[] args)

        {

            if(args.Length < 1)

            {

                Console.WriteLine("Usage: ConsoleApplication1.exe [Filename to test]");

                return;

            }

 

            string file = args[0];

            ShellFile so = ShellFile.FromFilePath(file);

            double nanoseconds;

            double.TryParse(so.Properties.System.Media.Duration.Value.ToString(), out nanoseconds);

            Console.WriteLine("NanaoSeconds: {0}", nanoseconds);

            if (nanoseconds > 0)

            {

                double seconds = Convert100NanosecondsToMilliseconds(nanoseconds) / 1000;

                Console.WriteLine(seconds.ToString());

            }

        }

 

        public static double Convert100NanosecondsToMilliseconds(double nanoseconds)

        {

            // One million nanoseconds in 1 millisecond, but we are passing in 100ns units...

            return nanoseconds * 0.0001;

        }

    }

}

As you can see, the System.Media.Duration Property returns a value in 100ns units so some simple math will turn it into seconds. Download the Test Project which includes the prebuilt WindowsAPICodePack.dll and WindowsAPICodePack.Shell.dll files in the bin folder:

ConsoleApplication1.zip (218.76 kb)

For the curious, I tested this on Windows XP and as you'd expect, it didn't work:

Unhandled Exception: System.DllNotFoundException: Unable to load DLL 'propsys.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

On Vista Ultimate SP2, it still didn't work - nanoseconds was always 0, though it didn't throw any exceptions.

For the older systems I guess we are limited to using the old MCI (Media Control Interface) API:

        using System.Runtime.InteropServices;

 

        [DllImport("winmm.dll")]

        public static extern int mciSendString(string lpstrCommand, StringBuilder lpstrReturnString, int uReturnLength, int hwndCallback);

 

        [DllImport("winmm.dll")]

        private static extern int mciGetErrorString(int l1, StringBuilder s1, int l2);

 

        private void FindLength(string file)

        {

            string cmd = "open " + file + " alias voice1";

            StringBuilder mssg = new StringBuilder(255);

            int h = mciSendString(cmd, null, 0, 0);

            int i = mciSendString("set voice1 time format ms", null, 0, 0);

            int j = mciSendString("status voice1 length", mssg, mssg.Capacity, 0);

            Console.WriteLine(mssg.ToString());

        }

Which works fine for .mp3 and .avi and other formats that play natively in Windows Media Player, but even with a codec pack installed, it doesn't work on Quicktime or .mp4 files, where the new Windows 7 API did.


Categories: C# | CodeProject | Windows | Windows 7
Posted by Williarob on Wednesday, October 21, 2009 12:14 PM
Permalink | Comments (0) | Post RSSRSS comment feed

New and Improved Microsoft AntiXss 3.1.

Until now, the preferred way to selectively allow only certain HTML tags like <b> and <i> was to regex the input to ensure it contained only valid Unicode letter and number characters and those specified tags, something like this:

if (!Regex.IsMatch(input, @"^([\p{L}\p{N}'\s]|<b>|</b>|<i>|</i>){1,40}$")) throw new Exception();

This approach will prevent all unwanted tags, but it will also prevent all attributes on the allowed tags. Sometimes this is good – attackers can add malicious script to onmouseover attributes of <b> and <i> tags – but again, sometimes this is overkill and blocks the use of benign attributes like lang or title. It would be theoretically possible to extend the regular expression to allow these attributes, as well as other safe HTML tags and their attributes, but realistically that would be an incredibly difficult regex both to develop and maintain.

AntiXss 3.1 takes care of all of this logic for you, using the same whitelist approach: it filters the input using a list of known good tags and attributes and strips out all other text. Simply pass the untrusted input through the AntiXss.GetSafeHtml or GetSafeHtmlFragment method to sanitize it:

string output = AntiXss.GetSafeHtml(input);

I strongly encourage everyone to download the new AntiXss 3.1 and incorporate it into your applications starting today. It’s a very effective defense, especially when used in conjunction with the output encoding functionality that’s been a part of AntiXss from the beginning.

Read the Full Article Here.

Download AntiXss 3.1 from Microsoft.


Posted by Williarob on Tuesday, September 29, 2009 1:50 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Shepherds Pie Recipe

Ingredients

1 tsp1 Worcestershire Sauce

1/4 tsp thyme

1/8 tsp pepper

1/4 tsp salt

1/8 tsp Paprika

2 tbsp2 Ketchup

1 tsp Parsley

1 Medium Onion

1 lb3 Ground Lamb (If you use Beef you're making Cottage Pie, not Shepherds Pie!)

2 Large Carrots

1 24oz4 Package Refrigerated Garlic Mashed Potatoes5

1 packet Gravy mix6

1 Cup7 Water

Directions

Peel & Chop the onion, then combine it and the ground Lamb in a large skillet over a medium heat. Meanwhile, peel and chop the carrots, then add them to the skillet and cover it, but don't forget to stir it occasionally while you work on the sauce.

In a small saucepan, add the gravy mix, Worcestershire Sauce, thyme, salt, pepper, paprika, ketchup, parsley and water. Mix it all up then put it on a high heat and keep stirring it until it boils (if you stop stirring it may get lumpy). When it boils, remove it from the heat. Assuming the meat is brown at this point, drain excess juices from the skillet and pour in the sauce. Cover the skillet and let it simmer over a low heat while you heat the potatoes.

Pour the contents of the skillet into a casserole or baking dish and add the potatoes evenly across the top, fluffing with a fork. I usually place the baking dish on top of a foil covered baking sheet to catch any drips, but that's because my dish is always packed to the very top with juicy goodness and it tends to make a small mess in the oven. Broil (Grill for those in Britain) until the potatoes are golden brown on top and a little crispy (about 5 mins). Serves 4.

Notes

  1. tsp = Teaspoon
  2. tbsp = Tablespoon
  3. 1 Pound (lb) = 0.45 kilograms (453.59 grams)
  4. 24 ounces is equal to 0.68 kilograms (680.39 grams)
  5. I use Bob Evans Garlic Mashed potatoes.
  6. An oxo/bovril cube gravy would be better, but very hard to come by in the US, so I use McCormick Brown Gravy mix which is a pretty good substitute.
  7. 1 cup is equal to 236.59 milliliters (ml)

Categories: recipes
Posted by Williarob on Monday, September 21, 2009 11:00 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Adobe Flex 3: Multiline text moves up by one line when selected

In Adobe Flex, <mx:Text> controls are selectable. When compiled into flash .swf files, you will be able to highlight that text using the mouse when it appears in your browser. However, we found that when you highlight the text in a dynamic multiline text control that text actually moves/scrolls up a line which in our case caused the top line of text to disappear. One solution is to set the selectable property to false, but this is not ideal.

Steps to reproduce:
1. Create a dynamic Text field in AS and assign a multi line string to htmlText and set selectable=true (alternatively use <mx:Text>".
2. Select any portion of the text with the mouse in a top to bottom motion.
3. The text will move up exactly one line making the first line of the text disappear.  

The problem seems to be that textField.setActualSize doesn't consider the leading property when calculating the size. This bug is documented here, and the solution is in the comments but unless you have edited the source of the Felx sdk before, you might not know how to take full advantage of it, so I thought I'd document the steps I took to correct the problem.

  1. First locate the file Text.as, which using the default install settings should be found here: C:\Program Files\Adobe\Flex Builder 3\sdks\3.0.0\frameworks\projects\framework\src\mx\controls
  2. Comment out line 342 which should look like this:

    textField.setActualSize(unscaledWidth - paddingLeft - paddingRight, unscaledHeight - paddingTop - paddingBottom);
  3. Insert the following code beneath it:

    var leading:Number = getStyle("leading");
    textField.setActualSize(unscaledWidth - paddingLeft - paddingRight, unscaledHeight - paddingTop - paddingBottom + leading);
  4. Go back to Adobe Flex and right click on your project and choose "Properties".
  5. Click on "Flex Build Path".
  6. Click on "Add Folder".
  7. Paste/type or browse to C:\Program Files\Adobe\Flex Builder 3\sdks\3.0.0\frameworks\projects\framework\src and click "OK".
  8. Click "OK" again to exit the properties dialog.
  9. Run your project again and hightlight the text. It should not move.

 

 


Categories: Flash | Flex
Posted by Williarob on Thursday, July 23, 2009 2:00 PM
Permalink | Comments (2) | Post RSSRSS comment feed

Working with Buttons inside a GridView Control

This post is as much for my benefit as anyone elses. Every few months I find myself scratching my head, wondering how I can find all the pieces of information I need inside the handler for a button click on a grid view.

Since I just had to do this again yesterday, this time, I'm going to record my findings here, so that next time I can come right to this page.

So here is the scenario: there is a GridView control on a page, bound to data in a database. It has multiple columns of read only data, but the last column contains a textbox and a button. When that button is pushed, I need to get the value of the text box, the orderid and the primary key of the current row in order to update a record in the database. I have found at least three ways to do this without getting too fancy.

      <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID" DataSourceID="SqlDataSource1">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="NAME" HeaderText="NAME" SortExpression="NAME" />
<asp:BoundField DataField="ORDERID" HeaderText="ORDERID" SortExpression="ORDERID" />
<asp:BoundField DataField="CITY" HeaderText="CITY" SortExpression="CITY" />
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox" ID="TextBox1" runat="server" Text='<%# Eval("PHONE") %>'
<asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton1_Click">Get Row Info</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>

The first way I'm going to explore may be considered rather "ghetto" in the sense that while it works beautifully it does bend some rules so anyone who tries to adhere to common patterns and practices would probably frown upon it. However, as you'll see, it does have a number of advantages over some of the more official techniques so don't rule it out right away! To use this ghetto code, add a RowDataBound event to your gridview and use it to find each instance of your button control and add some new attributes to it containing the information you'll need for this row:

protected void gv_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e)

    {

        GridViewRow gvr = (GridViewRow)e.Row;

 

        if (e.Row.RowType == DataControlRowType.DataRow)

        {

            // Find your controls

            LinkButton LinkButton1 = (LinkButton)gvr.FindControl("LinkButton1");

 

            // this is ghetto, but you can, add orderid and other data to attributes so we can grab them later           

            int orderId = Convert.ToInt32(DataBinder.Eval(e.Row.DataItem, "OrderID"));

 

            LinkButton1.Attributes.Add("OrderID", orderId);          

        } // end if this is a real row

    }

 

Obviously, if you choose to do this your linkbutton will be rendered with an OrderID attribute <a href="..." OrderID="123" ... /> which you can grab later when posting back. For example, if you add OnClick="LinkButton_Click" to your linkbutton inside the gridview, then inside LinkButton_Click you can get the orderID like so:

 

    protected void LinkButton1_Click(object sender, EventArgs e)

    {

        LinkButton lb = (LinkButton)sender;

        int orderID = int.Parse(lb.Attributes["OrderID"]);

        // ...

    }

 

It's quick, it works and while it doesn't seem like the "Microsoft approved" method to me, it is more scalable than the counting the cells (If your OrderID is rendered as a label in the third column, you might use Convert.ToInt32(row.Cells(2).Text); to obtain the orderid). But what happens when you or someone else adds an additional column to the gridview in front of orderid? Suddenly your orderid might be something else entirely and if it still compiles and runs perhaps no one will even notice!


Let's explore two more quick examples that adhere to what Microsoft had in mind. The first, again assumes you add OnClick="LinkButton_Click" to your linkbutton inside the gridview and that you need not only the orderid, but also the Primary Key and the value of TextBox1:

 

    protected void LinkButton1_Click(object sender, EventArgs e)

    {

        LinkButton lb = (LinkButton)sender;

        GridViewRow row = (GridViewRow)lb.NamingContainer;

 

        // get the value of the textbox

        TextBox txt1 = row.Cells[4].FindControl("TextBox1") as TextBox;

        string phoneNumber = txt1.Text;

 

        // get the Primary Key Value

        int ID = GridView1.DataKeys[row.RowIndex].Value;

 

        // ... Do something with these values like update a row in a database

    }

 

It is unfortunate that you cannot address a cell by anything other than its Index as if you later need to add another column in front of this one, your application will break. You might think this is no big deal, but consider what happens if you have this sort of code applied to two or three columns, and each one addresses multiple cells.

Then your boss asks you to add a new column. Trust me, you will groan, as you now have to recalculate the index of all cells addressed in this fashion. It can turn a 2 minute task into a 20 minute task.


As an alternative to the OnClick Event applied to an individual button, you can instead use the RowCommand Event of the GridView. This allows you to store some data inside the ComandArgument property of your button, which is arguably similar to the custom attribute method discussed at the beginning of this article, but since you can only set one command argument, if you need three pieces of information from it you are faced with a choice of either combining the information through concatenation - setting your command argument up as a string you plan to split apart later e.g. "OrderID=123|ProductID=456" or you are back to counting cells. And what's more, despite what this MSDN article implies, the CommandArgument does NOT contain the RowIndex by default, you would need to add it there yourself which can be done declaratively like so:

<asp:LinkButton ID="LinkButton1" runat="server"CommandArgument='<%# gv.Rows.Count.ToString() %>' CommandName="UpdatePhone">Get Row Info</asp:LinkButton>

Then your RowCommand Handler would look something like this:

 

       protected void GridView1_RowCommand(Object sender, GridViewCommandEventArgs e)

       {

            if (e.CommandName == "UpdatePhone")

            {

 

 

                // Convert the row index stored in the CommandArgument

                // property to an Integer.

                int index = Convert.ToInt32(e.CommandArgument);

 

 

                // Retrieve the row that contains the button clicked

                // by the user from the Rows collection.

                GridViewRow row = GridView1.Rows[index];

 

                // get the value of the textbox

                TextBox txt1 = row.Cells[4].FindControl("TextBox1") as TextBox;

                string phoneNumber = txt1.Text;

 

                // get the Primary Key Value

                int ID = GridView1.DataKeys[row.RowIndex].Value;

 

                // ... Do something with these values like update a row in a database

            }

        }

 

Conclusions


So there you have it. Three ways to Handle the onClick event of a button in a grid view. In my opinion, the OnRowCommand Event of the GridView is the least useful of them when trying to fulfil this brief. Sure it gives you the CommandArgument property, but you immediately need to use it for storing the row index. Whenever possible, I usually choose a Microsft approved approach so this time I opted for the OnClick event of the button but if I have to come back and add another column again, I'll probably use the custom attributes approach, because I do not want to have to increment/decrement all the cell index values again.


Categories: ASP.Net | C#
Posted by Williarob on Thursday, June 18, 2009 6:19 AM
Permalink | Comments (1) | Post RSSRSS comment feed

Asynchronous Programming with ASP.Net MVC Futures

Using the AsyncController

Introduction

The AsyncController is an experimental class offered inside the latest MVC Futures dll to allow developers to write asynchronous action methods.  The usage scenario for this is for action methods that have to make long-running requests, such as going out over the network or to a database, and don’t want to block the web server from performing useful work while the request is ongoing.

In general, the pattern is that the web server schedules Thread A to handle some incoming request, and Thread A is responsible for everything up to launching the action method, then Thread A goes back to the available pool to service another request.  When the asynchronous operation has completed, the web server retrieves a Thread B (which might be the same as Thread A) from the thread pool to process the remainder of the request, including rendering the response.  The diagram below illustrates this point.

Configuration

The asynchronous types are declared in the Microsoft.Web.Mvc namespace in the assembly Microsoft.Web.Mvc.dll.  The first change a developer needs to make is to declare a route as asynchronous.  There are MapAsyncRoute() extension methods to assist with this; these are analogs of the normal MapRoute() extension methods already provided by the MVC framework.  In Global.asax:

routes.MapAsyncRoute(

    "Default",

    "{controller}/{action}/{id}",

    new { controller = "Home", action = "Index", id = "" }

);

A route declared with MapAsyncRoute() can correctly handle both synchronous and asynchronous controllers, so there is no need to create complex routing logic such that sync controllers are serviced by the normal MapRoute() handler and async controllers are serviced by the MapAsyncRoute() handler.  However, a sync route [MapRoute()] cannot in general correctly execute async controllers and methods.

Secondly, if you are using IIS6 or IIS7 classic mode, you need to replace the standard *.mvc handler with its asynchronous counterpart.  Replace these lines in Global.asax (they don’t necessarily appear adjacent to one another):

<add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

With these:

<add verb="*" path="*.mvc" validate="false" type="Microsoft.Web.Mvc.MvcHttpAsyncHandler, Microsoft.Web.Mvc"/>

<add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="Microsoft.Web.Mvc.MvcHttpAsyncHandler, Microsoft.Web.Mvc"/>

Writing asynchronous action methods

In general, any asynchronous controllers that you author should subclass the AsyncController type.  Remember to import the Microsoft.Web.Mvc namespace.

public class MyAsyncController : AsyncController {

    // ...

}

The default constructor of the MyAsyncController sets the ActionInvoker property to an instance of the AsyncControllerActionInvoker.  This specialized invoker can understand several asynchronous patterns.  You can mix and match these patterns inside of your controllers.  If an ambiguity is found, we do our best to throw a detailed exception.

The AsyncController understands three async patterns.  These patterns can be mixed and matched within a single AsyncController.  Additionally, an AsyncController can contain normal (synchronous) action methods.  This makes it easy to change the base class of your controller from Controller to AsyncController in order to add async methods while allowing your original sync methods to run correctly.

The IAsyncResult pattern

The IAsyncResult pattern is a well-known pattern in the .NET Framework and is documented heavily.  A method pair signature which implements the IAsyncResult pattern is shown below.

public IAsyncResult BeginFoo(int id, AsyncCallback callback, object state);

public ActionResult EndFoo(IAsyncResult asyncResult);

This is the asynchronous analog of a synchronous method with the signature public ActionResult Foo(int id).  Note that the BeginFoo() method takes the same parameters as the Foo() method plus two extra – an AsyncCallback and a state object – and returns an IAsyncResult.  The EndFoo() method takes a single parameter – an IAsyncResult – and has the same return type as the Foo() method.

Standard model binding takes place for the normal parameters of the BeginFoo() method.  The invoker will pass a callback and state object for the BeginFoo() method to consume when its asynchronous task has finished.  When the callback is called, we automatically invoke the EndFoo() method and capture the result, then execute the result just as we would have in a synchronous request.

Only filter attributes placed on the BeginFoo() method are honored.  If a filter attribute is placed on EndFoo(), it will be ignored.  If an [ActionName] attribute is placed on the BeginFoo() method in order to alias it, we will look for an EndFoo() method based on the method name of BeginFoo(), not the aliased action name.  For example:

[ActionName("Bar")]

public IAsyncResult BeginFoo(int id, AsyncCallback callback, object state);

public ActionResult EndFoo(IAsyncResult asyncResult);

This will cause the BeginFoo() method to match requests for Bar rather than Foo.  Note that the completion method is still called EndFoo() instead of EndBar() since it matches the name of the entry method, not the entry alias.

The event pattern

In this pattern, the action method is divided into a setup method and a completion method.  The signatures are below:

public void Foo(int id);

public ActionResult FooCompleted(...);

When a request comes for Foo, we execute the Foo() method.  When the asynchronous operations are completed, we invoke the FooCompleted() method and execute the returned ActionResult.

The invoker will model bind parameters to the Foo() method in the standard way.  Parameters to FooCompleted() are not provided using model binders.  Rather, they come from the AsyncController.AsyncManager.Parameters dictionary, which can be populated as part of the asynchronous setup.  Keys in the dictionary correspond to parameter names of the FooCompleted() method, and any parameters which do not have corresponding keys in the dictionary are given a value of default(T).

The invoker must keep track of the number of outstanding asynchronous operations so that it does not invoke the FooCompleted() method prematurely.  To do this, a counter has been provided, accessible from AsyncController.AsyncManager.OutstandingOperations.  This counter can be incremented or decremented to signal that an operation has kicked off or concluded, and when the counter hits zero the invoker will invoke the completion routine.  For example:

public void Foo(int id) {

    AsyncManager.Parameters["p"] = new Person();

    AsyncManager.OutstandingOperations.Increment();

    ThreadPool.QueueUserWorkItem(o => {

        Thread.Sleep(2000); // simulate some work

        AsyncManager.OutstandingOperations.Decrement();

    }, null);

}

public ActionResult FooCompleted(Person p) {

    // consume 'p'

}

There is also an AsyncController.AsyncManager.RegisterTask() method that is helpful for wrapping calls to IAsyncResult pattern methods from within an event pattern method.  The RegisterTask() method also handles incrementing and decrementing the counter correctly.  For example:

public void Foo(int id) {

    AsyncManager.RegisterTask(

        callback => BeginGetPersonById(id, callback, null),

        ar => {

            AsyncManager.Parameters["p"] = EndGetPersonById(ar);

        });

    AsyncManager.RegisterTask(

        callback => BeginGetTotalUsersOnline(callback, null),

        ar => {

            AsyncManager.Parameters["numOnline"] = EndGetTotalUsersOnline(ar);

        });

}

public ActionResult FooCompleted(Person p, int numOnline) {

    // ...

}

This will kick off two asynchronous tasks and wait for both to finish before executing the FooCompleted() method with the values that were returned.

Only filter attributes placed on the Foo() method are honored.  If a filter attribute is placed on FooCompleted(), it will be ignored.  If an [ActionName] attribute is placed on the Foo() method in order to alias it, we will look for an FooCompleted() method based on the method name of Foo(), not the aliased action name.  For example:

[ActionName("Bar")]

public void Foo(int id);

public ActionResult FooCompleted(...);

This will cause the Foo() method to match requests for Bar rather than Foo.  Note that the completion method is still called FooCompleted() instead of BarCompleted() since it matches the name of the entry method, not the entry alias.

The Foo() method is allowed to return anything.  The invoker ignores the return value of this method; it only cares about the return value of the FooCompleted() method.  This is to allow writing Foo() methods that are easier to unit test.

The delegate pattern

This pattern is very similar to the event pattern, except that the method Foo() returns a parameterless delegate type and there is no FooCompleted() method.  For example:

public Func<ActionResult> Foo(int id) {

    Person p = null;

    int numOnline = 0;

    AsyncManager.RegisterTask(

        callback => BeginGetPersonById(id, callback, null),

        ar => {

            p = EndGetPersonById(ar);

        });

    AsyncManager.RegisterTask(

        callback => BeginGetTotalUsersOnline(callback, null),

        ar => {

            numOnline = EndGetTotalUsersOnline(ar);

        });

    return () => {

        ViewData["p"] = p;

        ViewData["numOnline"] = numOnline;

        return View();

    };

}

Or, more succinctly:

public Func<ActionResult> Foo(int id) {

    AsyncManager.RegisterTask(

        callback => BeginGetPersonById(id, callback, null),

        ar => {

            ViewData["p"] = EndGetPersonById(ar);

        });

    AsyncManager.RegisterTask(

        callback => BeginGetTotalUsersOnline(callback, null),

        ar => {

            ViewData["numOnline"] = EndGetTotalUsersOnline(ar);

        });

    return View;

}

Since this pattern supports only parameterless delegates instead of parameterful delegates, the earlier discussion about AsyncController.AsyncManager.Parameters is not applicable.

Timeouts

There is a Timeout property accessible from AsyncController.AsyncManager.Timeout that specifies the number of milliseconds to wait for a response from the action method before canceling the request.  The default value is 30000 (equal to 30 seconds).  If the action method has not returned by the specified time, we throw a TimeoutException.  Action filters and exception filters may handle this particular exception type if they wish.  Setting the Timeout property to System.Threading.Timeout.Infinite signifies that we will never throw this exception.

The timeout duration can be specified on a per-controller or per-action basis by attributing a class or method with [AsyncTimeout] or [NoAsyncTimeout].

Known issues

-          Asynchronous actions generally cannot be called by synchronous invokers or handlers.  If you receive an exception message about an action being unable to be executed synchronously, ensure that you’re using the MapAsyncRoute() extension method in your Global.asax and that your controller subclasses AsyncController.

-          The asynchronous invoker will not match any method beginning with Begin or End or ending with Completed.  This is to prevent web calls to the BeginFoo(), EndFoo(), and FooCompleted() methods directly.  If you need to make an action with this name accessible to web users, use the [ActionName] attribute to alias the method:

[ActionName("Begin")]

public ActionResult DoSomething();

The above is an example of a normal synchronous method that has been renamed to Begin to work around the invoker’s blocking of this name.

-          If the route that normally handles requests for the application root (/) is an asynchronous route, the Default.aspx file should be removed from the web application.  The Default.aspx file included in the template only works with synchronous requests.


Categories: ASP.Net | Asynchronous | C# | MVC
Posted by Williarob on Thursday, June 18, 2009 6:03 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Sample Scrolling Silverlight Video Playlist 2.0

Since the release of Silverlight 2, there have been a number of requests for me to update my Scrolling Silverlight Video Playlist Sample and I have finally made the time to do just that. I feel it is important to point out that Microsoft Expression Encoder 2 Service Pack 1 is now out and it ships with a handful of new Player templates just for Silverlight 2 including two with a built in Scrolling playlist feature (Frosted Gallery and Silverlight 2 Gallery). 

Still, partly because not everyone has Expression Encoder 2 and mostly because I felt it would be educational to do so, I went ahead and rebuilt the Scrolling Silverlight Video Playlist sample from the ground up for Silverlight 2 in C# and here it is:

This time, instead of using a player from the growing Expression Encoder template library, I went with the opensource Blacklight player which is a nice lightweight player. And rather than add my scroll widget directly to the player as I did with version 1.0, I chose to keep it seperate, and created a 'ScrollWidget' User Control that could be used in other projects (for example as a thumbnail scroller for photos, or as a toolbar) with only minor modification.

As always, the complete source code is available:

ScrollingPlaylist2.zip (1.22 mb)

[ Special thanks to Sean at FlawlessCode.com for developing this Silverlight Extension for BlogEngine.NET ]


Categories: C# | Silverlight
Posted by Williarob on Thursday, April 30, 2009 8:47 AM
Permalink | Comments (5) | Post RSSRSS comment feed

Using Expression Encoder 2 Silverlight 2 Templates in your project

Some time ago, I wrote a popular article on how to create a scrolling Silverlight 1.x Playlist using Microsoft Expression Encoder output. Well, I finally found some time to revisit that application to see how I might upgrade it to Silverlight 2. As you are probably aware, Expression Encoder 2 Service Pack 1 is now out and it ships with a handful of Player templates just for Silverlight 2. Among these new templates are two which already have built in Scrolling playlists and I thought I would test one out.

However, I already have all my videos encoded - including all the chapter point thumbnails, etc. so I didn't want to start inside Encoder, have it build my project and work from there like I did last time. This time, I created a new Silverlight 2.0 Usercontrol project in Visual Studio 2008 and worked for a week or two on the new look and feel for the site before I decided it was time to merge my project with the Expression Encoder template. I found Tim Heuer's blog entry on integrating these new templates very helpful, though I feel it is important to add that the template itself, meaning the look and feel of the player, is not stored in the dlls and it does not matter which of the template projects you open and compile, just referencing the dlls and following Tim's instructions will always give you the standard Silverlight 2 player. In order to add the look and feel you must copy (or merge) the contents of the Page.xaml file in that template into your own UserControl.

For my project I wanted the player to be a seperate UserControl, so I went to Project > New Item >  Silverlight User Control, and called it MediPlayer.xaml. Next I pasted everything from C:\Program Files\Microsoft Expression\Encoder 2\Templates\en\FrostedGallery\Source\Page.xaml into my new MediaPlayer.xaml file, then changed the x:Class at the very top to reflect my original NameSpace and Class Name. (If you forget what it was, just undo your paste, make a note of it and redo the paste).

I also wanted my Player control to be available on multiple pages, and I wanted it hidden most of the time, only to pop up in a pseudo modal 'Lightbox' format with a close button. To achieve this effect I simply used these techniques described by Scot Guthrie in his excellent tutorial on creating a Silverlight Digg application. So now I had my player, and I could show and hide it with the click of a button. Basically, my site showcases the James Bond Movies, and I have customized the Yet Another Carousel control so that you can click on the selected box art and read the synopsis, watch the Trailer and buy it on Amazon.com. My initial idea therefore, was to create a new PlayListItem programatically and add it to the player's PlayListCollection in the onLeftMouseButtonUp event of the button. What I found was that while this worked quite nicely, I ultimately ended up with a playlist slowly being generated by the user in the order in which the user clicked on the movies, making it harder to keep track of which item in the collection was which movie, but more importantly I couldn't figure out how to take full advantage of all the chapter information and thumbnails I had created for the original project. I could create chapter item objects, and add them to my own PlayListCollection object, but I could not bind that new object to my player since the Playlist Property is read only.

Reading more of Tim's blog I saw that you could add some xml to the InitParams of the control, but I have 24 videos, each with thumbnail paths for at least 4 chapter points and I didn't need to start typing that all into a single line to understand what a nightmare that would become: not only would it be hard to read and maintain but also it goes against the whole MVC seperation of code, data and presentation layers, ethic we have all grown so attached to.

More google searches led me to this solution which does allow you to move the creation of the parameters into the code behind, but seems to require tinkering with the original template code, which I am not opposed to, but I'd already thought of a cleaner solution. What I wanted was a way to create an xml file containing my entire playlist in this format:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <playList>
   3:   <playListItems>
   4:     <playListItem title="Dr No" description="Trailer" mediaSource="ClientBin/01_dr_no.wmv" adaptiveStreaming="False" thumbSource="ClientBin/01_dr_no_Thumb.jpg" >
   5:       <chapters>
   6:         <chapter  position="29.176" thumbnailSource="ClientBin/01_dr_no_MarkerThumb 00.00.29.1760677.jpg" title="1" />
   7:         <chapter  position="49.374" thumbnailSource="ClientBin/01_dr_no_MarkerThumb 00.00.49.3748838.jpg" title="2" />
   8:         <!-- etc -->
  20:       </chapters>
  21:     </playListItem>
  22:   </playListItems>
  23: </playList>

and simply pass the file to my player. And my Solution turned out to be trivially easy: I created a new class that inherits from ExpressionMediaPlayer.MediaPlayer, and added a new method that would accept my file:

 

using System;

using System.Diagnostics;

using System.Net;

using System.Windows;

using System.Windows.Browser;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Ink;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

using System.Xml.Linq;

 

 

namespace Bond_Silverlight2

{

    public class MI6MediaPlayer : ExpressionMediaPlayer.MediaPlayer

    {

        public MI6MediaPlayer(): base()

        {

        }

 

        public void OnStartup(string xmlPlayList)

        {

            XDocument document = XDocument.Load(xmlPlayList);

            try

            {

                Playlist.Clear();

                Playlist.ParseXml(HtmlPage.Document.DocumentUri, document.ToString());

            }

            catch (System.Xml.XmlException xe)

            {

                Debug.WriteLine("XML Parsing Error:" + xe.ToString());

            }

            catch (NullReferenceException)

            {

            }

        }

 

    }

}

 


This required some minor changes to the MediaPlayer.xaml file, inorder to make it use my version of the player:

First of all, I replaced the <expression:ExpressionPlayer> tags with <Bond_Silverlight2:MI6MediaPlayer> tags and any static resource styles that had a target type of ExpressionPlayer:ExpressionPlayer also needed to be replaced, and then everything used my new player. Obviously, there was another step - how to initialize and pass my xml playlist to my new player. First, I created my xml file in the format outlined above. It is important to note, that my video files and associated JPEG files are stored on the webserver inside the Clientbin folder, rather than inside the xap file as resources or content. In the code behind of my MediaPlayer.xaml (that is the usercontrol I pasted the page.xaml into earlier, not the MI6MediaPlayer class from the code above), I call the startup method using a link to my xml file:

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

 

namespace Bond_Silverlight2

{

    public partial class MediaPlayer : UserControl

    {

        public MediaPlayer()

        {

            InitializeComponent();

            this.Loaded += new RoutedEventHandler(MediaPlayer_Loaded);

        }

 

        void MediaPlayer_Loaded(object sender, RoutedEventArgs e)

        {

            Player1.OnStartup("Playlist.xml");

        }

 

        private void Button_Click(object sender, RoutedEventArgs e)

        {

            Player1.Stop();

            Visibility = System.Windows.Visibility.Collapsed;

        }

    }

}

 

The xml file ("Playlist.xml") is stored as Content within the xap file. This should be the default behavior if you created the xml file inside Visual Studio by using the Project > Add Item menu, but if you didn't, you can check by right clicking on the xml file, choosing Properties and checking that the Build Action is "Content", and Copy to Output Directory is set to "Do Not Copy".

Now when my Player is first loaded into memory, my full playlist is immediately available.

 


Posted by Williarob on Wednesday, April 08, 2009 1:47 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Error 1219. Multiple connections to a server

Occasionally, after connecting to a server using Sql Management Studio, Remote Desktop or through Windows Explorer using a file share and then trying to connect again using another of these methods I will be stopped by this error:

Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.

In the past I have rebooted to resolve the problem, but when you have half a dozen windows open this can be most inconvenient. Fortunately, I just found a better way:

Open a Command Prompt and type these commands:

net use (to see all existing connections)
net use * /del /yes (to delete all existing connections)


Categories: Networking | Windows | XP
Posted by Williarob on Thursday, March 12, 2009 10:38 AM
Permalink | Comments (1) | Post RSSRSS comment feed