Here I'm going to post whatever that is interesting for me. All things about programming using JavaScript and ASP.NET Core. And something else.

A blog about ASP.Net Core and JavaScript

Couple a days ago I was looking for some information about image uploading from external URL in an ASP.NET Core application. I‘ve found a great post written by Igor Sikorsky (see Sources [1]) and another one, which was written by Andrew Lock (see Sources [2]) who used the same approach.

But in Igor’s post discussion, someone noticed improper using of HttpClient to retrieve the image from external URL. Few seconds googling helped to find another interesting post by Simon Timms [3] which shows how to use HttpClient correctly. He suggests declaring a static instance of HttpClient in the .NET Core application main class.

It is cool, but what if I do not want to use HttpClient as a property of the main app class. What if I want to get it from DI service?

If you are interested in this approach too, welcome to read more…

Notes!

This post is from my old blog on Github.

I’ve used Visual Studio 2017 with latest updates to create simple ASP.NET Core 2.0 MVC Web application. After creating a new app with VS Wizard I have added new ImageController controller class and an Index view for it.

Next thing I have to do, accordingly to ASP.NET Core Documentation (see Sources [4]), is creating the interface and the class of the service to be used with dependency injection. Just a few lines of code :). I am using HttpClient instance as a private static member, and read-only property helps to get it from the DI service class.

Here is the source code of interface:

using System.Net.Http;
namespace ImageFromURL.Services
{
    public interface IHttpClientService
    {
        HttpClient Client { get; }
    }
}

And the source code of the class that realizes this interface:

using System.Net.Http;
namespace ImageFromURL.Services
{
    public class HttpClientService : IHttpClientService
    {
        private static HttpClient client = new HttpClient();
        public HttpClient Client
        {
            get
            {
                return client;
            }
        }
    }
}

 

After implementing the interface and the class they need to be registered in the app. The best place to do this is the ConfigureServices() method of the Startup class.

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // Add application services.
    services.AddTransient<IHttpClientService, HttpClientService>();
    services.AddMvc();
}

Now service is ready and we can use it. Let's do this! In the ImageController class constructor with the magic of dependency injection, we can get all the services we needed. In our case, those are hosting environment (to get app’s web root path) and just created HttpClientService service. Do not forget to create corresponding fields in the class.

public ImageController(IHostingEnvironment env, IHttpClientService clientService)
{
    hostingEnvironment = env;
    httpClientService = clientService;
}

The place, where we are going to use them, is the Index action bound to the POST method.

[HttpPost]
public async Task<IActionResult> Index(string externalUrl)
{
    if (string.IsNullOrWhiteSpace(externalUrl))
    {
        return View();
    }
    using (Image sourceImage = await LoadImageFromUrl(externalUrl))
    {
        if (sourceImage != null)
        {
            string path = hostingEnvironment.WebRootPath + uploadPath;
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            string fullPathName = path + filename;
            sourceImage.Save(fullPathName, ImageFormat.Jpeg);
        }
    }
    return View();
}

In the code above we are getting URL of the image that is hosted somewhere in the Web. Then with aid of LoadImageFromUrl() method, we are reading that picture to the Image instance. (Do not forget to nuget CoreCompat.System.Drawing.v2 library!). And lastly, we are saving the image to the host file system.

The LoadImageFromUrl() is the pretty same as Igor Sikorsky suggested in his example, except using HttpClient instance. We are using it as a property of received with dependency injection instance.

private async Task<Image> LoadImageFromUrl(string url)
 {
     Image image = null;
     try
     {
         using (HttpResponseMessage response = await httpClientService.Client.GetAsync(url))
         using (Stream inputStream = await response.Content.ReadAsStreamAsync())
         using (Bitmap temp = new Bitmap(inputStream))
             image = new Bitmap(temp);
     }
     catch
     {
         // Add error logging here
     }
     return image;
 }

The last thing to do is to implement Index view.

<form method="post" enctype="multipart/form-data" asp-controller="Image" asp-action="Index">
    <input id="externalUrl" name="externalUrl" type="url" style="width:100%" />
    <div class="buttons">
        <button type="submit">Submit</button>
    </div>
</form>

<div>
    <p>Image which is uploaded from URL.</p>
    <p>If you do not see it, may be you are running the app for first time.</p>
    <p>If you see the same image after uploading attempt, try to hit F5 or Ctrl+F5 to refresh the browser page.</p>
    <p>If you still do not see the image, probably you have caught the bug :)</p>
    <img src="~/uploads/image.jpg" />
</div>

Here we go! Hit F5 to run the project and see the result: 

The whole code solution with all the code above can be found on GitHub inside of the ImageFromURL repository.

Hope this post will be useful for someone :).

Sources

  1. ASP.NET Core Sample Image Resizing Service
  2. Using ImageSharp to resize images in ASP.NET Core - a comparison with CoreCompat.System.Drawing
  3. YOU’RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE
  4. Dependency injection into controllers