Attention: We are retiring the ASP.NET Community Blogs. Learn more >

Contents tagged with Visual Studio

  • Embedding JavaScript and Other Resources In a .NET Assembly

    One concept that I don’t see people using, understanding, or even being aware of much in .NET development circles is the Embedded Resource.  Declaring a file as an embedded resource within your project means that it will be compiled into the assembly, so that you don’t have to distribute the actual file with the assembly.

    In our projects, we embed many of the resources that we use, in order to reduce the number of files that we have to distribute.  The biggest use of this policy is towards JavaScript files.  We use a lot of JavaScript in our modules, but we don’t have to distribute any .js files, they all live in a .dll.  This also makes it a lot easier to automatically minify the JavaScript files when building, but that’s a story for another time.Properties page for swfobject.2.1.js with Build Action property selected

    Down at the end of this post, I’ll also talk about embedding files that are intended to be loaded in memory to be used, rather than accessed through the web.  In that case, it’s much more convenient to already have the file in the assembly, rather than having to search through the file system for it.

    So, how do you invoke this magic to place regular, non-compiled files into your compiled assemblies?  It all starts, as many things do, in Visual Studio.  With the file added to your project, take a gander at the file’s properties  (by pressing F4 if you don’t have some crazy keyboard setup).  The property page for a file is rather short, and we need to look no farther than the first property of the file to accomplish our purpose.  The Build Action property of the file is usually set to Content, meaning “[the] file is not compiled, but is included in the Content output group.”  By changing this to Embedded Resource, “[the] file is embedded in the main project build output as a DLL or executable.”  This is most of the magic we need, but we’re not quite done yet.

    Since this is a JavaScript file that we’ll want to access on the web, we need to tell the assembly that it’s okay to give the web access to the file.  If you miss this step, you’re going to get an error page instead of JavaScript when you try to reference it (and everything that depended on the script will be throwing errors both left and right).

    So, to accomplish this, we need to add an assembly-level attribute.  These usually live in the AssemblyInfo file, which, by default, is under the Properties folder of your project.  After adding a using/Imports of System.Web.UI, we can add the following WebResource attribute to our project (given a default namespace of “Engage.Demos.EmbeddedResources” and the file “swfobject.2.1.js” placed in a “JavaScript” folder):

        [assembly: WebResource("Engage.Demos.EmbeddedResources.JavaScript.swfobject.2.1.js", "text/javascript")]
    
    

    So, this brings us to the issue of naming.  The file is assigned a name when it is embedded into the assembly.  This name is the default namespace of the project, plus the folder path, plus the file name itself, all joined together with periods.  One important thing to note is that VB.NET assemblies do not have default namespaces (they have root namespaces, a source of continual confusion and frustration for C# programmers who switch back and forth).  Therefore, the resource names just start with the folder path.  In this case, the name would be "JavaScript.swfobject.2.1.js".

    Now that we’ve handled that, how do we actually get the script on the page?  The same way you get any script on the page, you use the ClientScriptManager (you do use the ClientScriptManager to manage your client scripts, right?).  This is accessible through the page’s ClientScript property, from which you can call RegisterClientScriptResource (when using an embedded resource, you don’t get to choose whether it is a “startup script” [added at the bottom of the page] or “script block,” [added at the top1] it’s always a “block”, so you can’t use the ClientScriptManager if you want to use this technique for a “startup script”).

    The RegisterClientScriptResource method takes a Type and the name of the resource.  The Type, as far as I can tell, is just used to provide an additional “namespace” for the include, i.e. trying to include the same resource twice with the same Type will result in only one script being added to the page, but if they have different Types specified, the script’ll be added twice.  So, in our case (working with a class called DemoPage), this looks like the following call during the page’s Load event:

        this.Page.ClientScript.RegisterClientScriptResource(typeof(DemoPage),
    "Engage.Demos.EmbeddedResources.JavaScript.swfobject.2.1.js");

    One notable time where this won’t work is when you are trying to add a script to the page during a partial postback.  In truth, you’ll probably have the same issue whether you’re embedding your JavaScript or not, but either way, the fix is to move from the ClientScriptManager to the ScriptManager (great naming for these two, don’t you think?).  For embedded scripts, use the static RegisterClientScriptResource method like you would with a ClientScriptManager instance, otherwise, pick between RegisterClientScriptBlock, RegisterClientScriptInclude, and RegisterStartupScript.  When using the ScriptManager methods, you’re required to add a line to the end of your script to notify the manager control that you’re script is done loading, but if your script is embedded into the assembly, it can do it for you and you’ll never have to wonder why the stupid thing isn’t working the way (you think) it’s supposed to work.

    If you have a case where you want to add a reference to an embedded script but the provided methods don’t work for you, you can use the ClientScriptManager.GetWebResourceUrl method to get a URL to that resource that you can use anywhere URLs are accepted, worldwide.

    Now, finally, what about files that aren’t JavaScript?  What if you have an XML schema that you want to load up to valid XML against?  Or what if you have an image that you want to add as a watermark to user-uploaded pictures?  In those cases, when you really want to load up the file within memory, rather than expose it to the web, the workflow is rather different.  At the most basic level, you’re going to use Assembly.GetManifestResourceStream to get a stream of the file.  The easiest way to get an assembly reference is to start with the type you’re in, and then access its Assembly property, like so:

        using (var schemaStream = typeof(DemoPage).Assembly.GetManifestResourceStream(typeof(DemoPage), 
    "Schemas.DemoSchema.xsd"))
    {
    // validate something...
    }

    One further note about naming.  In this situation, the first Type parameter is used to lend its namespace to the resource, so, in this case, since the full name of DemoPage is Engage.Demos.EmbeddedResources.DemoPage, I don’t have to specify the Engage.Demos.EmbeddedResources part of the resource’s name. 

    From there, you can go wild, doing whatever you want to do with the stream of your file.

    Hopefully this clears some things up, and hopefully introduces you to a tool that you may not have known about or may not have known enough about.  Make sure and let me know if you have any questions, or see any better ways to go about this stuff.

     


     

    1 The ClientScriptManager actually only messes with the form element on the page, so it’s really the top and bottom of the page’s form that’s where the scripts get placed. 

  • C# Compiled DotNetNuke Module Template

    It shouldn't be hard to get started writing a module for [DotNetNuke], but it doesn't seem like there's a whole lot of help especially when you are wanting to use C#.  At Engage, we have created a Visual Studio project template which will get you started developing a C# [DotNetNuke] module, using a Web Application project (rather than the, in my opinion, much more cumbersome Web Site project).  It is available for free on our downloads page after registering on the site.

    The template will get you started with the basics of a [DotNetNuke] module, providing basic placeholder controls (for view, edit, and settings), base classes to use for your module controls and your settings control, a manifest and NAnt build file to easily package your module, and the basic starting point (and sample code) for your business controller class and data provider.  It should really speed up how you start a new module, and free you from always copying your last module and then having to figure out what to delete and what to leave.

    To use the template, put the downloaded zip file into the C# web templates folder for Visual Studio.  This is typically in My Documents/Visual Studio [2005|2008]/Templates/ProjectTemplates/Visual C#/Web (you might have to create the Web folder yourself).  This will make the new project type appear under the Web node for C#, in the My Templates section, when you create a new project.  You might also want to open up the zip file and alter the template manifest (C# Compiled Module.vstemplate) to include your company name (replace the values in the CustomParameters section where it says YourCompany).

    Please check it out, we hope it helps you out.  Happy module building!

    [Cross-posted from http://www.engagesoftware.com/Blog/EntryID/162.aspx]