How to get a PDF from Server Side to Client Side?

So you generate a PDF in the C# code or any back end code, but need to send it back to the JavaScript doing the AJAX request. The trouble is how do you return a file back to the client side, which is the same problem I faced. There are loads of methods of how to do this that I have seen on the line, but these are the ways I found worked with C#.NET and JavaScript consistently.

Returning the File

First method I found was very simple and the most direct route to the user. In this scenario you do an AJAX request from the JavaScript straight to the back end system that is generating the PDF file and return that file in the request.

First get the file from the file system into a ‘FileStream’:

Var filesFullPath = "C:\documents\pdfDocument.pdf";
Var fileStream = new FileStream(filesFullPath , FileMode.Open, FileAccess.Read, FileShare.Delete, 4096, fileOptions);

Then use the ‘ControllerBase.File’ class, part of the Controllers inherited class, to convert the ‘FileStream’ into a ‘FileResult’ with a PDF content Type:

Var fileResult = ControllerBase.File(fileStream, "application/pdf");

‘ControllerBase’ is part of the inherited ‘Controller’ Class from ‘Microsoft.AspNetCore.Mvc’.

You can then return this object back to the requesting JavaScript. On the client side it is just a standard ‘XMLHttpRequest’, but the key part is the ‘responseType’ is set to ‘arrayBuffer’.

This means when the response comes back in that format we can create a new ‘Blob’ from the object with the correct content type. This Blob is then converted to a URL and opened in a new window.

var url = "<a href="http://www.GetMyPdf.com/GetPdf">http://www.GetMyPdf.com/GetPdf</a>";

// Send Request
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.responseType = 'arraybuffer';
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onload = function (e) {

// Check status
if (this.status == 200) {

// convert response to Blob, then create URL from blob.
var blob = new Blob([this.response], { type: 'application/pdf' }),
fileURL = URL.createObjectURL(blob);

// open new URL
window.open(fileURL, '_blank');

} else {

console.error('response: ', this);

}
};

xhr.send(JSON.stringify(data));

Now this works great in the scenario above, but a situation that we came against was the back end code to the client side was not doing the generating there was a middle tier, then also it was handling the response from all APIs as a json response which is a string type. Therefore we couldn’t return the file directly and not in an Array Buffer format.

A better solution would be to store the PDF file somewhere the client side can request it after it has been generated. This will save on the large packet of data being sent back and less worry of data loss, but let us continue on this path anyway.

The solution to the weird request is to use Base64 as the string based response. In the C# code we can convert the file into ‘bytes’, which can then be converted to Base64 string:

var fileFullPath = "C:\documents\MyPdf.pdf";

// Convert to Bytes Array
bytes[] pdfBytes = File.ReadAllBytes(fileFullPath );

// Convert to Base64
var base64Str = Convert.ToBase64String(pdfBytes);

This is then saved to return back as a string to the middle tier and then back to the client side.

We now have a string response that we can to convert the Baset64 into a PDF file for the client, which can work both of these ways.

If you first prefix the Base64 with the PDF Base64 DataURI as below:

var base64Str = "****";
var base64DataUri = 'data:application/pdf;base64,' + base64Str;

You can then open the Data URI in a window:

// open new URL
window.open(base64DataUri , '_blank');

However I didn’t find this consistently working, so instead I do the same as before with the ‘XMLHttpRequest’, but instead the URL is the Data URI.

var url = base64DataUri;

// Send Request
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.responseType = 'arraybuffer';
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onload = function (e) {

// Check status
if (this.status == 200) {
// convert response to Blob, then create URL from blob.
var blob = new Blob([this.response], { type: 'application/pdf' }),
fileURL = URL.createObjectURL(blob);

// open new URL
window.open(fileURL, '_blank');

} else {

console.error('response: ', this);
}
};

xhr.send();

This now uses the base64 string as the URL to request the PDF as a web request so we can return the PDF as a Byte Array, then just like before it is converted to a Blob, to URL and opened in a new window.

So far this has worked and consistently, so try it out and give me any feedback.

Resharper DotCover Analyse for Visual Studio Team Services

Do you use Visual Studio Team Services (VSTS) for Builds and/or Releases? Do you use Resharper DotCover? Do you want to use them together? Then boy do I have an extension for you!

That might be a corny introduction, but it is exactly what I have here.

In my current projects we use Resharpers, or also know as Jet Brains, DotCover to run code coverage on all our code. However to run this in VSTS there is a bit of a process to install DotCover on the server and then write a Batch command to execute it with settings. This isn’t the most complex task, but it does give you a dependency to always install this on a server, and have the written Batch script in source control or in the definitions on VSTS. This can cause issues if you forget to get it installed or you need to update the script for every project.

Therefore I got all that magic of the program and cramed it into a pretty package for VSTS. This tool is not reinventing the wheel, but putting some greese on it to run faster. The Build/Release extension simply gives you all the input parameters the program normally offers and then runs them with the packaged version of DotCover that comes with the extension. See simply.

There is however one extra bit of spirit fingers I added into the extension. When researching and running my own tests, I found that some times it is helpful to only run the coverage on certain projects, but to do this you need to specify every project path in the command. Now I don’t know about you, but that sounds boring, so I added an extra field.

Instead of in the Target Arguments passing each project separately and manually, you can pass wildcards in the Project Pattern. If you pass anything in the Project Pattern parameter it will detect you want to use this feature. It then uses the Target Working Directory as the base to recursively search for projects.

For Example: Project Pattern = “*Test.dll” and Target Working Directory = “/Source”

This will search for all DLL that end with ‘Test’ in the ‘Source’ directory and then prepend it to any other arguments in the Target Arguments.

For Example: “/Source/MockTest.dll;/Source/UnitTest.dll”

You can download the extension from the VSTS Marketplace
Here are is a helpful link for Resharper DotCover Analyse – JetBrains
Then this is the GitHub Repository for any issues or some advancements you would like – Pure Random Code GitHub

Update 20-07-2018

There was a recent issue raise on the GitHub Repository that addressed a problem I have also seen before. When running the DotCover from Visual Studio Team Services an error appears as below:

Failed to verify x64 COM object registration: Empty path to COM object.

From the issue raise, the user had linked to a Community Article about “DotCover console runner fails when running as VSTS task“, which in the comments they discussed how to fix this.

To correct it we simply add the following command to the request, that specifies what profiled process bitness to use as they say.

/CoreInstructionSet=[x86|x64]

Therefore the task has now been updated with this field and feature to accomadate this issue and fix. It has been run and tested by myself plus the user that raised the issue, so please enjoy.

How to merge multiple images into one with C#

Due to a requirement we needed to layer multiple images into one image. This needed to be faster and efficient plus we didn’t want to use any third party software as that would increase maintenance. Through some fun research and testing I found a neat and effective method to get the outcome required by only using C#.NET 4.6.

So the simple result was to use the C# class ‘Graphics’ to collect the images as Bitmaps and layer them, then produce a single resulting Bitmap.

As you can see from below, we first create the instance of the end Bitmap by create a new type with the width and height of the resulting image passed in. Using that Bitmap we create an instance of the Graphics, which we use in our loop of each image. For each of the images, they are added to the graphic with the starting X/Y co-ordinates of 0.

This solution solves the requirement I had as they all needed to be layered from the starting point of the top left corner, but you could also get imaginative with the settings to place the layers in different places, or even with the Bitmaps width you could create a full length banner.

// merge images
var bitmap = new Bitmap(width, height);
using (var g = Graphics.FromImage(bitmap)) {
foreach (var image in enumerable)     {      
g.DrawImage(image, 0, 0);
    }
}

This is of course handy and simple, so I thought to share and help I would create a full class to handle the processing. With the class below you do not need to create an instance as it is static, so that it can be used as a tool like it is.

You can find the full code on my Github at https://github.com/PureRandom/CSharpImageMerger

The aim of this class which can be expanded, is to layer an array of images into one. You can do this by passing an array of links, of bitmaps or a single folder directory.

When you pass the array of links, you also have the option of providing proxy settings depending what your security is like. It then uses an inside method to loop each link to attempt to download it and return them in a bitmap list.

private static List ConvertUrlsToBitmaps(List imageUrls, WebProxy proxy = null) {
    List bitmapList = new List();
    // Loop URLs
    foreach (string imgUrl in imageUrls)
    {
      try
      {
        WebClient wc = new WebClient();
        // If proxy setting then set
        if (proxy != null)
        wc.Proxy = proxy;
        // Download image
        byte[] bytes = wc.DownloadData(imgUrl);
        MemoryStream ms = new MemoryStream(bytes);
        Image img = Image.FromStream(ms);
        bitmapList.Add((Bitmap)img);
      }
      catch (Exception ex)
      {
        Console.Write(ex.Message);
      }
      }
    return bitmapList;
}

When you pass the array of bitmaps it is the same as the above, but it doesn’t have to download anything.

Finally the file system method can be used by passing the folder directory you wish it to search, then the image extension type. So if you was looking to merge all png’s in the directory ‘src/images/png’, then that is what you pass.

private static List ConvertUrlsToBitmaps(string folderPath, ImageFormat imageFormat)
{
    List bitmapList = new List();
    List imagesFromFolder = Directory.GetFiles(folderPath, "*." + imageFormat, SearchOption.AllDirectories).ToList();
    // Loop Files
    foreach (string imgPath in imagesFromFolder)
    {
      try
      {
        var bmp = (Bitmap) Image.FromFile(imgPath);
        bitmapList.Add(bmp);
      }
      catch (Exception ex)
    {
      Console.Write(ex.Message);
      }
      }
    return bitmapList;
}

With all of these it then uses the common method to loop each item in the array of bitmaps for find the biggest width and height, so the images don’t over or under run the results size. As explained above, each bitmap is looped through to merge the images to the top left of the result Bitmap to create the final image.

private static Bitmap Merge(IEnumerable images)
{
  var enumerable = images as IList ?? images.ToList();
  var width = 0;
  var height = 0;
  // Get max width and height of the image
  foreach (var image in enumerable)
  {
    width = image.Width > width ? image.Width : width;
    height = image.Height > height ? image.Height : height;
  }
  // merge images
  var bitmap = new Bitmap(width, height);
  using (var g = Graphics.FromImage(bitmap))
  {
    foreach (var image in enumerable) {
      g.DrawImage(image, 0, 0);
    }
  }
  return bitmap;
}

Feel free to comment, expand and share this code to help others.

https://github.com/PureRandom/CSharpImageMerger