Make package deployment easy with single file deployment

Recently I've deploying GoogleMap Editor package to Umbraco community.

During development I realized that package will have to include script, some html templates, images... I had no problem with that but when it came to actual package build I realized that I will have to deal with bunch of files and even during development, so se some changes which were not dll related I had to restart app by touching web.config.

It was a great time loss since I was developing the whole thing whenever I had few hours or minutes of my free time. Everything would be much easier if I could restart the app (by building the dll) and have everything at one place.

Also, storing a project to source control would be a lot easier if all could be part of a project. I embedded resources and all files I needed were packed in dll itself, but the problem was how to make them available in Umbraco.

Then WebAPI came into the whole story. First I developed static methods to retrieve values from resources.

using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Web; namespace Umbraco.GoogleMaps { public static class Common { public static string GetResourceText(string filename) { string result = string.Empty; var assembly = Assembly.GetExecutingAssembly(); var resourceName = string.Concat("Umbraco.GoogleMaps.Resources.", filename); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) if (stream != null) { using (StreamReader reader = new StreamReader(stream)) { result = reader.ReadToEnd(); } } return result; } public static Bitmap GetResourceBitmap(string filename) { Bitmap result = null; var assembly = Assembly.GetExecutingAssembly(); var resourceName = string.Concat("Umbraco.GoogleMaps.Resources.", filename); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) if (stream != null) { result = new Bitmap(stream); } return result; } public static Stream GetResourceStream(string filename) { Stream result = null; var assembly = Assembly.GetExecutingAssembly(); var resourceName = string.Concat("Umbraco.GoogleMaps.Resources.", filename); using (Stream stream = assembly.GetManifestResourceStream(resourceName)) if (stream != null) { result = stream; } return result; } } }

Because I retrieved not only text, but images too, I created additional method to make it easier and not instantiation bitmap wherever I needed in upper level code.

Now these needs to available to the rest of the website. We are going to need WebAPI methods now, but because we want to force the return data format in exposed WebApi methods we need some custom filters. Because I have some JavaScript files I will use the following filter to ensure that JavaScript accept type is set for the request.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Http.Filters; using System.Web.Http.Controllers; using System.Web.Http; using System.Net.Http.Headers; namespace Umbraco.GoogleMaps.ApiFilters { public class ReturnJavaScriptOnly : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { actionContext.Request.Headers.Accept.Clear(); actionContext.Request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/javascript; charset=utf-8")); } } }

Now we write controller for Umbraco WebApi method

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Umbraco.Web.WebApi; using Umbraco.GoogleMaps.ApiFilters; using System.Web.Http; using System.IO; using System.Web; using System.Drawing; using System.Net.Http; using System.Net.Http.Headers; using System.Drawing.Imaging; using System.Net; namespace Umbraco.GoogleMaps.Controllers { public class ResourceController : UmbracoApiController { [ReturnJavaScriptOnly] public HttpResponseMessage GetEmbdededJavaScript(string filename) { string result = Common.GetResourceText(filename); return new HttpResponseMessage() { Content = new StringContent(result, System.Text.Encoding.UTF8, "application/javascript") }; } public HttpResponseMessage GetEmbededGif(string filename) { HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); MemoryStream ms = new MemoryStream(); Common.GetResourceBitmap(filename).Save(ms, ImageFormat.Gif); HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new ByteArrayContent(ms.ToArray()); result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/gif"); return result; } public HttpResponseMessage GetEmbededPng(string filename) { HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); MemoryStream ms = new MemoryStream(); Common.GetResourceBitmap(filename).Save(ms, ImageFormat.Png); HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new ByteArrayContent(ms.ToArray()); result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); return result; } } }

Now embedded files are available and can be fetched by get on /Umbraco/WebApi/<Controller name>/<Method name>

One of the examples is in partial view which is included in the package I developed.

if (typeof GoogleMapViewer == 'undefined') { document.write(unescape("%3Cscript src='/Umbraco/Api/Resource/GetEmbdededJavaScript?filename=jquery.googlemapview.js' type='text/javascript'%3E%3C/script%3E")); }

More code and usage you can find at the package source on GitHub or by downloading the package itself from Umbraco community website. The URLs are in references section.

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.