I'm going to start this off by saying that I am, by no means, a SharePoint expert. Developing for SharePoint is painful, but also rewarding. When it works, you feel an immense amount of pride that your solution worked after all of your labor. However, there's the immeasurable pain and headaches that come from attempting to write it.
That being said, I did find a very
clever way of embedding a piece of content (in my case, a Silverlight xap -- but this could be anything, a JPEG, PNG, MP3, etc) into a SharePoint webpart. Given my background of making
everything work on multiple platforms, I wanted to have the
simplest possible way of doing this, without having to continually go back and forth with new code. Given I'm also trying to write a platform of tools and controls, this enables me to make a standardized package where we're not going to have conflicts with different versions of a chunk of content in the layouts folder with different assemblies/features installed.
The jist of this is that we're going to have ASP.NET share the content through a compiled DLL. Seems complicated? Not as much as you'd think. It's a relatively simple process:
- Add content to your project.
- Add information about the resource to your assembly.
- Utilize the resource.
First things first -- make sure you have a SharePoint project setup in Visual Studio 2010. I imagine this will probably work in prior versions of Visual Studio, but I haven't tested it.
1. Add content to your project.
Originally, I wanted to do things the "right" way for embedding my content -- I wanted to add each file into the mapped Layouts folder that Visual Studio 2010 gracefully provides. However, a minor issue arose from this -- my content is changing dynamically, and I needed to add it as a linked item (like the way I've done with Silverlight and WPF controls). Since the file is linked and not actually in the folder, Visual Studio doesn't have it in the directory and thus, it is not built. You could potentially make a script to copy it back/forth after the content is built (in my case, it's a Silverlight xap), but then you have issues with checking it out, etc.
Instead, we want to link it, since that's much, much, much easier. It prevents a lot of issues that could also result with conflicting and different features, in the event of any major issues with deployment.
So, I created a folder in my project called "Resources" where I would link this in. In this example, I have a Silverlight application called "HelloWorld.xap" and will be linking in the existing xap from the Release directory.
Make sure that this is included as an "Embedded Resource" from the "Build Actions."
Gotta love our Hello World applications!
Now, that we have that done, we can get to the slightly uglier part.
2. Add information about the resource to your assembly.
In the SharePoint project, we need to open up AssemblyInfo.cs under Properties and edit it very minorly. We want to add in the new resource we have. I had to add in a reference to System.Web, and you likely will too.
At the bottom of the file, you will need to add one entry per resource, as follows:
[assembly: System.Web.UI.WebResource("EmbeddedSPContent.Resources.HelloWorld.xap", "application/x-silverlight-2")]
The first parameter of System.Web.UI.WebResource is the name of the file and its location in the project. Notice that to notate paths/directories, we need to use periods instead of slashes.
The second parameter of System.Web.UI.WebResource is the mime-type. What do you want the DLL to tell the browser that the file is? In my case, I want it to be recognized as a Silverlight application. This could potentially be a PNG, MP3, and so forth.
Still hanging on there? Cool, because we're almost done.
3. Utilize the resource.
Ah, yes -- the most important part. We have to actually use it now. But that's simple. I'm going to build a pretty standard WebPart and override RenderContents.
I added the following code to render it (a very quick/dirty Silverlight HTML mockup):
string resourceUrl = Page.ClientScript.GetWebResourceUrl(GetType(), "EmbeddedSPContent.Resources.HelloWorld.xap");
string control = @"
<div id=""silverlightControlHost"">
<object data=""data:application/x-silverlight-2,"" type=""application/x-silverlight-2"" width=""400px"" height=""400px"">
<param name=""source"" value=""{MY_URL}"" />
<param name=""minRuntimeVersion"" value=""4.0.50826"" />
<a href=""http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50826.0"" style=""text-decoration:none"">
<img src=""http://go.microsoft.com/fwlink/?LinkId=108181"" alt=""Get Microsoft Silverlight"" style=""border-style:none"" />
</a>
</object>
</div>";
control = control.Replace("{MY_URL}", resourceUrl);
writer.Write(control);
and look at the below, it works!
I know what you're thinking -- that's a sexy web part.
The sample is included on MSDN for others to use, so this will hopefully make it easier to follow what was done:
http://code.msdn.microsoft.com/Embedding-Resources-for-d61b251d
Please note that in order to get this working, we have to deploy it as a Farm Solution, rather than a Sandboxed Solution.