Displaying Pictures in ASP .NET MVC

    Technologies: .NET Framework 3.5, ASP.NET MVC
    Languages: Visual Basic .NET, C #

    Quite often, when developing web applications, it is necessary to give the user data in a format other than html. For example, display a small copy of the image (ThumbImage), or return protected data from the database. In ASP .NET WebForms, you can use Handlers or regular ASPX pages for these purposes. In ASP .NET MVC, things have changed a bit. Although of course, as before, nothing is forbidden to use handlers. Unless, you may need a rule for Routing , such as: routes.IgnoreRoute ("{resource} .ashx") .
    This review will consider an example of image output using ASP .NET MVC tools, however, the described approach can be used to output data of absolutely any format.


    Actionresult



    As you know (I hope that it is known), the result of the execution of any action (action) of the controller (controller) is ActionResult. ActionResult is a base class from which all classes inherit, ultimately generating content for output to the client. For example: ViewResult, JsonResult, ContentResult, RedirectResult, etc. By itself, the ActionResult class cannot be used, you can only inherit from it, and due to this, the list of results of the controller actions is limited only by the imagination of the developers.
    The data for output is generated in the ExecuteResult method .

    Imageresult



    Actually, so that the controller can give the image to the client, you need to write your class inherited from ActionResult. Logically, his name should be ImageResult, but that's up to you.

    VB .NET: C #:
    Public Class ImageResult
      Inherits ActionResult
    End Class



    public class ImageResult: ActionResult
    { }


    As I already said, content is generated in the ExecuteResult method, however, before you do this, you need to get the source material. In other words, pass information to the class on the basis of which the final data will be generated. In the case of images, it will most universally pass to the Stream class. It will also be necessary to transmit information about the type of content (Content-Type) so that search engines are not afraid, and browsers do not guess on the coffee grounds and, as a result, do not injure the user's psyche. To do this, you will have to write a couple of relevant properties, and to complete the picture, register a constructor.

    VB .NET: C #: To conclude this, you need to write code for the ExecuteResult method, in which the image will be displayed based on the received data. VB .NET: C #:
    Private _ImageStream As Stream
    Private _ContentType As String = ""

    Public Property ImageStream() As Stream
      Get
        Return _ImageStream
      End Get
      Set(ByVal value As Stream)
        _ImageStream = value
      End Set
    End Property

    Public Property ContentType() As String
      Get
        Return _ContentType
      End Get
      Set(ByVal value As String)
        _ContentType = value
      End Set
    End Property

    Public Sub New(ByVal imageStream As Stream, ByVal contentType As String)
      If imageStream Is Nothing Then Throw New ArgumentNullException("imageStream")
      If String.IsNullOrEmpty(contentType) Then Throw New ArgumentNullException("contentType")
      _ImageStream = imageStream
      _ContentType = contentType
    End Sub



    private static Stream _ImageStream;
    private static string _ContentType = "";

    public static Stream ImageStream
    {
      get { return _ImageStream; }
      set { _ImageStream = value; }
    }

    public static string ContentType
    {
      get { return _ContentType; }
      set { _ContentType = value; }
    }

    public ImageResult(Stream imageStream, string contentType)
    {
      if (imageStream == null) throw new ArgumentNullException("imageStream");
      if (String.IsNullOrEmpty(contentType)) throw new ArgumentNullException("contentType");
      _ImageStream = imageStream;
      _ContentType = contentType;
    }





    Public Overrides Sub ExecuteResult(ByVal context As System.Web.Mvc.ControllerContext)
      If context Is Nothing Then Throw New ArgumentNullException("context")
      Dim Response As HttpResponseBase = context.HttpContext.Response
      Response.ContentType = _ContentType
      Dim buffer(1024) As Byte
      Do
        Dim read As Integer = _ImageStream.Read(buffer, 0, buffer.Length)
        If read = 0 Then Exit Do
        Response.OutputStream.Write(buffer, 0, read)
      Loop
      Response.End()
    End Sub



    public static override void ExecuteResult(System.Web.Mvc.ControllerContext context)
    {
      if (context == null) throw new ArgumentNullException("context");
      HttpResponseBase Response = context.HttpContext().Response;
      Response.ContentType = _ContentType;
      byte[] buffer = new byte[1024];
      do
      {
        int read = _ImageStream.Read(buffer, 0, buffer.Length);
        if (read == 0) { break; }
        Response.OutputStream.Write(buffer, 0, read);
      } while (true);
      Response.End();
    }


    Now the result of the action of any controller can be ImageResult.

    VB .NET:
    Return New ImageResult(System.IO.File.OpenRead("C:\kbyte.ru.gif"), "image/gif")

    C #:
    return new ImageResult(System.IO.File.OpenRead("C:\\kbyte.ru.gif"), "image/gif");

    Extension



    For complete happiness, you can write an extension for System.Web.Mvc.Controller. To do this, users can create a regular module (Module), and vice versa a static class, with a name, for example ControllerExtensions , and write in it several convenient functions that ImageResult will return.

    Note. Remember to import the System.Runtime.CompilerServices namespace .

    VB .NET: C #: Now in the controllers you can use the prescribed functions, for example: VB .NET: C #:
    Public Module ControllerExtensions

       _
      Public Function Image(ByVal controller As System.Web.Mvc.Controller, ByVal imageStream As Stream, ByVal contentType As String) As ImageResult
        Return New ImageResult(imageStream, contentType)
      End Function

       _
      Public Function Image(ByVal controller As System.Web.Mvc.Controller, ByVal imageBytes() As Byte, ByVal contentType As String) As ImageResult
        Return New ImageResult(New MemoryStream(imageBytes), contentType)
      End Function

       _
      Public Function Image(ByVal controller As System.Web.Mvc.Controller, ByVal fileName As String, ByVal contentType As String) As ImageResult
        Return New ImageResult(System.IO.File.OpenRead("C:\kbyte.ru.gif"), contentType)
      End Function

    End Module



    public static class ControllerExtensions
    {

      [Extension()]
      public static ImageResult Image(System.Web.Mvc.Controller controller, Stream imageStream, string contentType)
      {
        return new ImageResult(imageStream, contentType);
      }

      [Extension()]
      public static ImageResult Image(System.Web.Mvc.Controller controller, byte[] imageBytes, string contentType)
      {
        return new ImageResult(new MemoryStream(imageBytes), contentType);
      }

      [Extension()]
      public static ImageResult Image(System.Web.Mvc.Controller controller, string fileName, string contentType)
      {
        return new ImageResult(System.IO.File.OpenRead("C:\\kbyte.ru.gif"), contentType);
      }

    }





    Return Image(System.IO.File.OpenRead("C:\kbyte.ru.gif"), "image/gif")


    return Image(System.IO.File.OpenRead("C:\\kbyte.ru.gif"), "image/gif");

    Afterword



    Inheriting from the ActionResult class, you can display data of absolutely any format. What functionality of the code will be registered in the ExecuteResult method depends entirely on your imagination. As for images, if you will output images from files, I would recommend that you read them in advance (make a copy, for example, in an array of bytes) so that you do not accidentally lock files if you need to manipulate them (over files) in the future (moving, deleting).

    -
    Nemiro Alexei,
    06/29/2009

    Also popular now: