The name of the blog was inspired by the C#using statement that allows programmers to specify when objects that use resources should release them; and in the same way, you can use my tips, tricks, and try-outs at your own disposal ;)


Juicy Presentation Pattern for SharePoint (JUIPP)

 Have you ever asked yourself, why ASP.NET WebForms is not replaced by ASP.NET MVC? Or are you just waiting for the next SharePoint version to support ASP.NET MVC? Or, perhaps you inpatiently tried to integrate ASP.NET MVC to SharePoint yourself? If yes, read on, I might just have what you are looking for.

Let me give you the bad news first (arguable bad), Microsoft is not positioned to replace ASP.NET WebForms with ASP.NET MVC. Let’s just get that once and for all. SharePoint is heavily integrated with ASP.NET WebForms, going back and rebuilding SharePoint with ASP.NET MVC would be a wrong move because it would take so much time with no business value in return. ASP.NET WebForms is working great for SharePoint, and Microsoft would actually continue to promote both paradigm hand-in-hand. SharePoint Developers especially dealing with farm solutions involving Visual Web Parts and Application Pages would continue to use ASP.NET WebForms. In fact, SharePoint 13 is still using ASP.NET WebForms (4.0).

I am not going to compare and contrast the two paradigm, otherwise will spend all day arguing (Dino Esposito, has a great article just on that here). But for the sake of making a point, let me list few good stuff:


  • Separation of Concerns (SoC) that you get from the upfront division of your application into loosely-coupled components
  • Embracement of HTML and HTTP giving you more rendering control
  • And of course the testability of your code without spinning the whole ASP.NET runtime

ASP.NET WebForms:

  • The event-driven programming model
  • A higher level of abstraction
  • Very mature 3rd party tools (my favorite is Telerik ASP.NET AJAX)

Guest what? nothing stops you from bringing all 3 bullets listed under ASP.NET MVC to ASP.NET WebForms. It’s just difficult! To bring in SoC, you have to design your application with discipline from the ground-up with Object-Oriented principles in mind. After all, MVC is not a technology, it’s a conceptual presentation design pattern that existed since the late 70s, and evolved from a classic MVC model to MVP, MVVM (or PM) and others, and the pattern can be applied at any level of abstraction or technology (you can even apply it in your daily life). And, of course with SoC, testability would be apparent. Point making the MVC pattern is not owned by ASP.NET MVC.

ASP.NET WebForms does not give you guidely into how to structure your application or where to put your business logic. But it gives you a lot of power, and like my Ruby on Rails professor would say “With great power comes great lack of Separation of Concerns”.

So, how do we close the gap for my dearest SharePoint and ASP.NET WebForm Developers?

Juicy Presentation Pattern! JUIPP in short is a set of libraries and tools that promote convention over configuration to ASP.NET WebForms. Convention over Configuration (CoC) is a common design philosophy where you favor to follow conventions over explicit application configuration. When you use JUIPP, you abide to specific rules governed by naming conventions, well-defined file structure, clear communication mechanisms and component responsibilities. When correctly following the rules, JUIPP helps you focus on the unconventional part of your application and enables you to maintain your application in a consistent manner.

The goal of the Juicy Presentation Pattern project is to have an open source community that would gradually inject Separation of Concerns (SoC), favor Convention-over-Configuration (CoC) for consistent and maintainable application, and emphasize modularization for easier Test-Driven Development  (TDD) for ASP.NET WebForms, therefore for SharePoint Visual Web Parts and Application Pages (_layouts pages).

To download the framework and get more information please visit As it is a work in progress, any comment or suggestion is very much appreciated.

Thank you,

using NaT


Looking SharePoint Topologies as Patterns (MOSS 2007)

When I first had to deal with SharePoint 2007 server topologies I had to understand the different possible configurations so I can come up with a configuration that takes performance, availability, redundancy and flexibility in to account. So, I thought it would be cool to think of SharePoint server configurations as patterns and anti-patterns and be able to identify them quickly without going into details and be able to communicate it to others.

To start with, let me just define what design patterns in Software engineering are (got it from Wikipedia):

Pattern: a design pattern is a general reusable solution to commonly occurring problem in software design.

Anti-Pattern: an anti-pattern is a design pattern that may be commonly used but is ineffective and/or counterproductive in practice.

SharePoint Server Roles

Let me first describe the different server roles in SharePoint 2007.

Be aware: it's targeted for MOSS 2007 (not SharePoint 2010).


Any server in SharePoint that has the “Windows SharePoint Services Web Application” service is a Web-Front-End. That means your Web Applications is configured on each one of the web-front-ends and can potentially receiver requests from end-users through IIS Web Sites.

Whether a WFE serves end-users or not matters on which one of the WFEs you load balance and expose it to end user requests. So that means just because a server has the “Windows SharePoint Services Web Application” service installed, it does not mean it is receiving requests from end-users (very important point).



A server with a query role is a search server in SharePoint that has the “Office SharePoint Server Search” service running and configured for serving search queries.

SharePoint out-of-the-box can load balance the query role for you. That means you can have more than one server with the query role.


A server with a query role is a server in SharePoint that has the “Office SharePoint Server Search” service running and configured for indexing content.

SharePoint by design cannot load balance the index role. That means you can only have one server having the index role, unless you configure another SSP (you can only have one index per SSP).



A server with an excel role is a server in SharePoint that has the “Excel Calculation Service” running. It is basically used to do excel calculation and render excel content to SharePoint sites. And, this role can be load balanced easily by SharePoint.


A server hosting the Central Administration Web Application



A database server (or cluster) hosting the content databases, the configuration database and other SharePoint databases.


The Standalone Configuration

I will start with the standalone configuration, because that’s where all the anti-patterns arise. The standalone configuration is basically having all the roles on a single server and we will branch out patterns and anti-patterns from it.


The Anti-Patterns

Propagation Anti-Pattern

One of the common mistakes when configuring an application server is assigning the same server the Query and Index role. Don’t ask me why, but for some reason if the index finds the query role on the same box, the indexer assumes that there is no other server in the farm that has the query role, therefore does not propagate index to other query servers. So, don’t forget! Make sure you don’t assign the query and index role for the same server and assume other load balanced query servers to be functional.


Disk-I/O Anti-Pattern

Database Operations really depends a lot on the physical storage, and a lot of Disk I/O happens on a database server. Because of that, having the WFE role on the same server will affect the performance of the SharePoint site because the worker process will compete with the database server for resources. And this is actually the first thing you should avoid, as you will improve your SharePoint site performance significantly if you have the database role on a dedicated box.

Exposed-CA Anti-Pattern

A common mistake you can make, is hosting the central administration Web Application on a Web Front End (a web front end that actually serves requests). Say, the WFE box is compromised, that would expose the central administration for an attack (you wouldn’t want that, would you?). You need to take care of one thing though, the central administration web application located on a complicatedly separate box could still be vulnerable, and so you need to plan how to protect the central admin box from the WFEs (be it with some kind of firewall, or whatever).  


The Patterns

Database-Separation Pattern

Like I mentions on the Disk-IO anti-pattern, you can easily increase your SharePoint site performance by having a dedicated server. And, that’s the first thing you should consider, therefore the Database-separation pattern.

Request-Separation Pattern

This pattern separates the Web-Front-End from the Application server. Using this pattern, you solve 2 major issues:

  • By separating the WFE from the CA, you can have a chance to protect the Central Administration Web Application.
  • The indexing can consume server resources. So, separating the WFE from the indexer will be another performance boost after applying “The database separation pattern”.

Query-Separation Pattern

I mentioned earlier that if the index and query are on the same box, the index will not propagate index on to other query servers. So, by separating the query role into a different server, you avoid the propagation issue and at least you give yourself the flexibility to add more query servers as you need them (note that I have the WFE and the Query role on the same box, if you only have 3 boxes then that’s the best way to go, but if you anticipate a lot of query requests it might be a good idea to have a dedicated query server).


Target-Box Pattern

Didn’t we talk about “The exposed-CA anti-pattern” and “the competing-Indexer anti pattern” earlier? Then, WTF is the WFE role doing with the CA and Index role? The answer is simple: I am not really using the second WFE for end-user requests (the one with the CA and other roles), it’s not load balanced or does not get end-user requests at all. I can even hide it behind a firewall. The reason I have it: is to avoid the request load on the end-user WFEs that is coming from the indexer. You basically have a target box for the indexer. Target box pattern also avoids the extra hop on the network, because the calls from the indexer would be local.


Request-Load-Balancing Pattern

You have applied “The database separation pattern”, “The request separation pattern”, “The query separation pattern”, and you have avoided the exposure of the CA, you have increased the performance of the WFE, and you have given the query a chance for load balancing.

So, now it’s time to care for your Web-Front-Ends. By adding a second WFE not only you make your SharePoint more available (if one is down, you got the other still running) but you also increase performance by distributing request loads. Note that, your query request is also load balanced, this makes your farm more available (if one query is down, the other will take it).


Available-Database Pattern

When you first applied “The database-separation pattern”, you gained a significant performance. Now, you should plan how to make your server available. Pretty simple, you use SQL Server clustering. Take note here, that SharePoint doesn’t really know about the database cluster; SharePoint just refers to the database as if it was a single server. And, it’s pretty much the job of SQL server to manage the cluster. You pretty much have two options when clustering database servers: Active-Active or Active-Passive clustering. You either have both as active or you can have one active and the other passive where one of the database servers is active and the other stays inactive and waiting for the other to fail and take over, therefore “The available-Database pattern” (I am not an expert on this subject but you can use the technique of Database Mirroring to make your database redundant).


X5 Pattern

When you apply “The database-separation”, “The request-separation”, “The query-separation”, “The target-box”, “The available-database” and “the request-load-balancing” patterns, you end up with a minimum of 5 servers forming an X, therefore I call it the X5 pattern. Note that if you’re avoiding “The propagation anti-pattern” and trying to load balancing search then you pretty much end up assigning the query roles to both WFEs.


Web-X6 Pattern

This is pretty much the X5 pattern, with one additional server targeted for Web request. From applying the X-5 pattern we ended up load balancing the query role on both WFEs, and now you might need to plan to have an additional WFE not to over kill the 2 WFEs. That also gives you a chance to just leave the index alone and separate the Excel to the 3rd WFE or perhaps load balance the Excel role between the 3rd WFE and the application box. With this pattern, you can pretty much load balance WFE, Query and perhaps Excel services.

App-X6 Pattern

The Web-X6 pattern can perhaps fit for a farm where WFEs do a lot of user authentication for collaboration reasons (authentication could be expensive, so therefore an additional WFE would definitely help). On the other hand, The Application-X6 pattern targets the query role. If you are expecting a lot of search queries, then it might be a better idea to have a dedicated query server than having a 3rd WFE, for that reason you add a 2nd application server and that can primarily be used for query but you can also use it to host a second CA or separate the CA from the index server (btw if you are having the CA with Query server you can perhaps stop IIS, and start it back whenever you need it, that way you don’t have to worry about having using up the memory), and you can also use the same box to load balance the Excel Role if Excel services availability is very important.



This was more of an excercise to go through the process of identifying and understand the different topologies. Please make sure you research and plan before you configure your farm, and don’t take the patterns black-and-white, as you have to come up with your own topology that best fits your budget and your business.






How to programmatically authenticate to UAG protected SharePoint

this post is not a how-to configure UAG and SharePoint for Authentication. It's about how to programmatically authenticate to UAG and use the SharePoint Client Object Model under the following scenario.

The scenario:

<!   Your SharePoint Site is behind a Forefront Unified Access Gateway (UAG) that’s configured to have a single login experience with SSO, by providing you a login page that redirects you to the appropriate ADFS protected SharePoint Content.


For the SSO to work, UAG has to issue cookie based security token to the user before the SharePoint content can be delivered. When you hit your public SharePoint URL for the first time, UAG responses back with an automatic redirection taking you to a form-based UAG login page. When the user submits their credentials, the cookie-based security token generated by UAG is submitted behind the scene. UAG will then validate the credentials and approves the cookie-based security token. At this point any request to the SharePoint URL with the approved cookie-based security token will be granted access to the SharePoint content.

Now, what happens when you connect to the SharePoint URL programmatically?

After UAG redirects you to a login Page, it sends you back cookie-based security tokens that you are supposed to submit along with your credentials. If you don’t use the cookies, you will be stuck in a loop where UAG will keep redirecting you till you provide a cookie container, and you would reach the maximum automatic redirection allowed by your http request. Therefore you get the following error: “Too many automatic redirections were attempted” (I talk about this, because that's the first issue I encountered, when dealing witht UAG and SharePoint authentication).


If you are creating a .NET client application connecting to SharePoint, you would either build proxies against the SharePoint Web Services or use the SharePoint Client Object Model. I choose to use the SharePoint Client Object Model because it’s simpler, especially because I don’t have to worry about passing canary value (X-Request Digest Information), because that is already taking care of behind the scene.

So the first thing you should figure out is how you can pass cookies to each HTTP requests that the SharePoint Client Object Model uses. The answer is simple: Create an event handler to Microsoft.SharePoint.Client.ClientContext ExecutingWebRequest event that initializes a cookie container for the underlying HTTP Request before doing anything. And add the UAG approved cookies to the cookie container.


How to get the UAG approved cookies:

<!   1.   Do a GET on https://SharePointURL

2.    2. Get the cookie from the Response

      3. Construct the UAG Login Page URL

      4. Do a POST to the UAG Login Page URL with the correct credentials along with the cookie

<!  5. Then pass the cookie to the ClientContext’s underlying HTTP Request using the event handler.


I have created a class called CookieAuthenticator that will do the first 4 steps for you and returns the cookies that you can add to the SharePoint client context underlying HTTP request.




using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net;

using System.IO;


namespace net.usingnat.SharePoint.Uag


    public class CookieAuthenticator


        NetworkCredential Credential





        string Url





        string UserAgent





        private CookieCollection Cookies





        private string[] Queries





        private string ValidationUrl






        private void Connect()


            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.Url);

            request.CookieContainer = new CookieContainer();

            request.UserAgent = this.UserAgent;


            //Do a GET on the SharePoint URL

            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())


                //Get the UAG generated cookies from the response

                this.Cookies = response.Cookies;


                //Get the query strings to construct login page URL

                this.Queries = response.ResponseUri.Query.Substring(1).Split(new string[] { "&" }, StringSplitOptions.RemoveEmptyEntries);

                this.ValidationUrl = this.Url;


                //Construct the login page URL

                for (int i = 0; i < response.ResponseUri.Segments.Length - 1; i++)


                    this.ValidationUrl += response.ResponseUri.Segments[i];


                this.ValidationUrl += "Validate.asp";



        private void ValidateCredentials()



            //Construct the POST HTTP Request Data

            ASCIIEncoding encoding = new ASCIIEncoding();

            string postData = string.Empty;

            postData += string.Format("user_name={0}", this.Credential.UserName);

            postData += string.Format("&password={0}", this.Credential.Password);

            postData += string.Format("&repository={0}", "AD");


            foreach (var query in this.Queries)


                if (query.Contains("site_name=")

                    || query.Contains("resource_id=")

                    || query.Contains("secure=")

                    || query.Contains("login_type="))

                postData += "&" + query;



            byte[] data = encoding.GetBytes(postData);



            //Do a POST on the Login Page URL

            HttpWebRequest postRequest = (HttpWebRequest)WebRequest.Create(this.ValidationUrl);

            postRequest.ContentType = "application/x-www-form-urlencoded";

            postRequest.ContentLength = data.Length;

            postRequest.CookieContainer = new CookieContainer();

            foreach (Cookie cookie in this.Cookies)




            postRequest.Method = "POST";

            postRequest.AllowAutoRedirect = true;

            using (Stream newStream = postRequest.GetRequestStream())


                newStream.Write(data, 0, data.Length);



            //get back the cookies

            using (HttpWebResponse response = (HttpWebResponse)postRequest.GetResponse())


                this.Cookies = response.Cookies;






        public CookieAuthenticator(string url, string userAgent, NetworkCredential credentials)


            this.Url = url;

            this.UserAgent = userAgent;

            this.Credential = credentials;



        public CookieCollection Authenticate()




            return this.Cookies;






Sample Program (How to pass the cookie to the ClientContext):


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Web;

using System.IO;

using Microsoft.SharePoint.Client;

using System.ComponentModel;

using System.Data;

using System.Net;


namespace net.usingnat.SharePoint.Uag


    class Program


        private CookieCollection cookies;


        static void Main(string[] args)


            var program = new Program();





        public void GetData()


            using (ClientContext ctx = new ClientContext("https://SharePointURL"))


                ctx.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>(ctx_ExecutingWebRequest);


                ctx.AuthenticationMode = ClientAuthenticationMode.Default;

                var list = ctx.Web.Lists.GetByTitle("Documents");





                Console.WriteLine("Title: " + list.Title);

                Console.WriteLine("Description: " + list.Description);

                Console.WriteLine("Count: " + list.ItemCount);





        public void Authenticate()


            Console.WriteLine("Enter your username: ");

            var userName = Console.ReadLine();

            Console.WriteLine("Enter your password: ");

            var password = Console.ReadLine();

            var url = "https://SharePointURL";

            var userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv: Gecko/20101203 Firefox/3.6.13";

            var credentials = new NetworkCredential(userName, password);


            var authenticator = new CookieAuthenticator(url, userAgent, credentials);


            this.cookies = authenticator.Authenticate();



        private void ctx_ExecutingWebRequest(object sender, WebRequestEventArgs e)


            e.WebRequestExecutor.WebRequest.CookieContainer = new CookieContainer();

            foreach (Cookie cookie in this.cookies)










The next step should be how to sign-out from UAG. Well, if you figure that out please let me know.




Using NaT




Add-SPSolution : "Access Denied" Vicious Circle (SharePoint 2010)

If you get an "Access Denied" when trying to deploy a SharePoint solution using PowerShell in SharePoint 2010, then you probably did not run PowerShell as "Run as Administrator" or/and you are not a ShellAdmin.

So, just right-click PowerShell and click "Run as Administrator". If that does not work you then just run Get-SPShellAdmin and see if your account you are using is listed as a ShellAdmin. Initially, only the "Farm Admin" service account is a ShellAdmin (not the "Setup Admin" service account). If your account is listed, then I am sorry I wouldn't know what to say. But, if not then use the Add-SPhellAdmin to add your account. You might run here into a vicious circle where you would still get "Access Denied" when running Add-SPShellAdmin. In this case just login as the "Farm Admin" service account and then add your initial account as a Shell Admin.

At this point, you can login back with your initial account, "Run As Administrator", and then run Add-SPSolution, and hopefully it works for you (finger crossed).

using (NaT)



Audio file support in a SharePoint Document Library

Add an audio file into a SharePoint document library and try to open it. You will get the following message if you are using IE 8 (or previous version of IE):


If you upload audio files to a regular document library, SharePoint will sends back the file request as MIME Type of “text/html” (maybe text/plain) instead of “audio/wav” (or something similar audio type). For that reason, IE is not smart enough to detect the content is in fact an audio file to launch the appropriate application, perhaps Windows Media player (Google Chrome can actually detect it and play the audio file in-browser).

The solutions I can think of are the following:

Solution-1: Change your document library view to “Explorer View”, and it will basically detect any file type in your document library as if they were in your local machine. Keep note that it is actually running system commands and that might be unsafe.

Solution-2: Create an HttpModule to intercept requests to the SharePoint Web application, detect if an audio file has been request, then respond back with a MIME type “audio/wav” instead of “text/html”, and then let the browser detect the audio file and open its appropriate windows application.

Solution-3: Create a custom Field Type that uses a form-rendering control that figures out the URL of the audio and embeds a windows media player to play the audio when item is in “View Properties” mode. Then, make use of your new custom field type in your SharePoint document library.

Solution-4: Dynamically add “Play” Edit Control Block for audio items, and when clicked it navigates to a SharePoint application page that plays the audio in-browser Windows Media Player.

Solution-1 is slick and quick way of solving it, if users are willing to run system commands of course. Solution-2 is theoretically feasible. Effects are at the web application level, which makes it interesting, and worth looking at, as you can apply the same concept to other non-supported files in SharePoint Document libraries. Solution-3 sounds possible too. In fact I first started out this road, and realized it will need more effort and time than I expected it would (If possible I might give it a shot sometime, at least to explore the intrinsic involved in custom field types, RenderPattern elements and form-rendering controls). But, if you like the idea of having a “Play” ECB specifically added for audio files and let’s you play audios from your browser without opening other apps in your machine, then solution-4 is what you are looking for.

Here you find sample codes. Sample codes!!!! In other words, you have to clean it up on your own.

But anyways, the followings are the different components of solution-4:

  • Audio Library: A SharePoint document library containing audio files (ex: files with extension .wav)
  • Audio-Check Service: a SharePoint application Page used as a simple web service that can determine whether an item in SharePoint is an audio file or not. All it does is receive a SharePoint item URL, uses the Object Model to determine the extension of the file, then responses back a Boolean value in an XML format.
  • Content Editor Web Part: added on the same page as the List View Web Part of the audio library. It will contain JavaScript codes that uses SharePoint JavaScript Context object and XHR object to make Ajax calls to Audio-Check Service, determines whether or not a document is an audio file, and depending on the result decides to put the “Play” edit control block for only audio files.
  • Audio Player Page: a SharePoint application page that receives an audio file URL and plays audio on a page using embedded Windows Media Player.

Audio-Check Service

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Web;
   6: using Microsoft.SharePoint.WebControls;
   7: using Microsoft.SharePoint;
   8: namespace NaT.SharePoint.EditControlBlockAudioSupport.WebControls
   9: {
  10:     public class AudioCheckService : LayoutsPageBase
  11:     {
  12:         protected WindowsMediaPlayer _mediaPlayer;
  13:         protected override void OnLoad(EventArgs e)
  14:         {
  15:             base.OnLoad(e);
  17:             string itemId = this.Request.QueryString["ItemID"];
  18:             string listId = this.Request.QueryString["ListID"];
  19:             string audioCheck = this.Request.QueryString["AudioCheck"];
  22:             if(audioCheck != null)
  23:             {
  24:                 SPList list = this.Web.Lists[new Guid(listId.Trim())];
  25:                 SPListItem item = list.GetItemById(Int32.Parse(itemId.Trim()));
  26:                 bool displayEditControlBlock = this.IsItemAnAudioFile(item);
  27:                 this.ResponseDecision(displayEditControlBlock);
  28:             }
  29:         }
  31:         public bool IsItemAnAudioFile(SPListItem item)
  32:         {
  33:             return item.File != null && item.File.Name.EndsWith(".wav");
  34:         }
  36:         public void ResponseDecision(bool decision)
  37:         {
  38:             this.Response.ClearHeaders();
  39:             this.Response.ClearContent();
  40:             this.Response.Cache.SetCacheability(HttpCacheability.NoCache);
  41:             this.Response.AddHeader("Content-type", "text/xml");
  42:             this.Response.Write(@"<?xml version=""1.0"" encoding=""UTF-8"" ?>");
  43:             const string cmdPattern = @"<Command>{0}</Command>";
  44:             this.Response.Write(string.Format(cmdPattern, decision.ToString().ToLower()));
  45:             this.Response.End();
  46:         }
  47:     }
  49: }


Audio Player Page

For playing back audio you can use <OBJECT /> HTML Tag for embedding Windows Media Player in your browser, it let’s you pass a URL as a parameter and streams it back for you.

type="application/x-oleobject" height="500px" width="500px">
<PARAM NAME="SendPlayStateChangeEvents" VALUE="True" />
<PARAM NAME="AutoStart" VALUE="true" />
<PARAM NAME="AnimationAtStart" VALUE="true" />
<PARAM NAME="ShowControls" VALUE="true" />
<PARAM NAME="ShowAudioControls" VALUE="true" />
<PARAM NAME="ShowTracker" VALUE="true" />
<PARAM NAME="EnableTracker" VALUE="true" />
<PARAM NAME="ShowStatusBar" VALUE="true" />
<PARAM NAME="ShowDisplay" VALUE="true" />
<PARAM NAME="AudioStream" VALUE="true" />
<PARAM NAME="ShowPositionControls" VALUE="true" />
<PARAM NAME="EnableFullScreenControls" VALUE="true" />
<PARAM name="uiMode" value="none" />
<PARAM name="PlayCount" value="1" />
<PARAM name="FileName" value="{1}" />

Create a Web Control that uses the <OBJECT /> Tag. I would prefer putting the Object Tag format in a different embedded file have that loaded in your Window Media Player Web Control:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Web;
   6: using System.Web.UI;
   7: using System.Web.UI.WebControls;
   9: namespace NaT.SharePoint.EditControlBlockAudioSupport.WebControls
  10: {
  12:     public class WindowsMediaPlayer : WebControl, INamingContainer
  13:     {
  14:         public string FileName{ get; set;}
  15:         protected override void Render(HtmlTextWriter writer)
  16:         {
  17:             base.Render(writer);
  18:             var template = this.GetResourceFileAsString("NaT.SharePoint.EditControlBlockAudioSupport.Properties.MediaPlayerObject.xml");
  19:             var outputMarkup = string.Format(template, "MediaPlayer_" + Guid.NewGuid().ToString(), FileName);
  20:             writer.Write(outputMarkup);
  21:         }
  22:         private static string GetResourceFileAsString(string fileName)
  23:         {
  24:             var assembly = Assembly.GetExecutingAssembly();
  25:             var stream = assembly.GetManifestResourceStream(fileName);
  26:             if (stream != null)
  27:             {
  28:                 var streamReader = new StreamReader(stream);
  29:                 var myText = streamReader.ReadToEnd();
  30:                 if (myText != null) return myText;
  31:             }
  32:             return string.Empty;
  33:         }
  34:     }
  35: }

Then, basically use the above WindowsMediaPlayer Web Control in your Media Player SharePoint application page.


Content Editor Web Part – JavaScript

   1: <script language="javascript">
   2: function IsAudioFile(m, ctx, itemId)
   3: { 
   4:    var request;
   5:    var url = ctx.HttpRoot + 
   6:     "/_layouts/NaT.SharePoint.EditControlBlockHandler/AudioCheckService.aspx?ListID=" + 
   7:     ctx.listName + "&ItemID=" + itemId+ "&AudioCheck=true";
   9:    if ( window.XMLHttpRequest )
  10:    {
  11:       request = new XMLHttpRequest();
  12:"GET", url, false);
  13:       request.send(null);
  14:    }
  15:    else if ( window.ActiveXObject )
  16:    {
  17:       request = new ActiveXObject("Microsoft.XMLHTTP");
  18:       if ( request )
  19:       {
  20:"GET", url, false);
  21:          request.send(); 
  22:       }
  23:    }
  24:    if ( request )
  25:    {   
  26:       var commands = request.responseXML.getElementsByTagName("Command");
  27:       var cmdName = commands[0].firstChild.nodeValue;
  28:       if(cmdName == "true") return true;
  29:       else return false;
  30:    }
  31: }
  34: function Custom_AddDocLibMenuItems(m, ctx)
  35: {
  36:     if(IsAudioFile(m,ctx, currentItemID) == false) return false;
  37:     strAction="window.navigate(ctx.HttpRoot+;
  38:     '/_layouts/NaT.SharePoint.EditControlBlockHandler/AudioCheckService.aspx?ItemFileUrl='+
  39:     ctx.HttpRoot+currentItemFileUrl)"
  41:     CAMOpt(m,"Play",strAction,"");
  42:     CAMSep(m);
  44:     return false;
  45: }
  48: </script>


Your final out come should be something like this:

Play ECB


And, after clicking “Play”, you will be navigated to the media player application page.


Happy coding,