Display Image Result of API to WEB - asp.net-mvc

The retrieval and image conversion from byte to image is working great
API CODE:
[HttpGet]
public HttpResponseMessage MemberImage(string employeeId)
{
IMemberProcedures storedProcedure = new StoredProcedure();
IValidation validation = new CommonRepository();
RequestModel request = SQL.Read(out List<MemberDetail> members, storedProcedure.SAMPLESTOREDPROCEDURE("::1", employeeId));
byte[] imgData = members[0].Picture;
MemoryStream ms = new MemoryStream(imgData);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(ms);
response.Content.Headers.ContentType = new
MediaTypeHeaderValue("image/png");
return response;
}
Trying this in postman returns a fully converted image
Now I wanted to display that image to my Web and this is what I have tried;
WEB CODE:
[HttpGet]
public ActionResult MemberImage(string id)
{
IGetInterface Ip = new IpHelper();
HttpResponseMessage image = API.GetResponse($"api/QMS/MemberImage?employeeId={id}");
var foo = image.Content.ReadAsStringAsync().Result;
return File(Enumerable.Range(0, foo.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(foo.Substring(x, 2), 16))
.ToArray(), "image/png");
}
This triggers an error of Unsupported Media and I dont think I am doing the right way of displaying the image from web controller to my view.
Is there any other way on displaying image result of API to WEB?

Finally after several retries I got it working by using ReadAsByteArrayAsync().
[HttpGet]
public ActionResult MemberImage(string id)
{
IGetInterface Ip = new IpHelper();
HttpResponseMessage image = API.GetResponse($"api/QMS/MemberImage?employeeId={id}");
byte[] foo = image.Content.ReadAsByteArrayAsync().Result;
return File(foo, "image/png");
}
Display it to view by doing this;
<img src='#Url.Action("MemberImage", new { id = Model.Member.EmployeeNumber })'>

Related

MVC Image - Dispaly in a Tab instead of downloading to a file

I have the following controller method which gets a PNG from a web api.
public async Task<ActionResult> RealTimeUpdate(string fundName)
{
string docPath = ConfigurationManager.AppSettings["RealTimeUpdate"].Replace("{fundname}",fundName).ToString();
docPath = docPath.Replace("\\\\", "\\");
docPath = docPath.Replace("\"", "");
string url = ServiceUrl + "api/RealTime/" + fundName;
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var dataStream = response.Content.ReadAsStringAsync().Result;
if (dataStream == null)
return HttpNotFound();
var _buffer = JsonConvert.DeserializeAnonymousType(dataStream, new { _buffer = (byte[])null })._buffer;
// If user decides to save the file, this will help...
//Response.AddHeader("content-disposition", "filename=" + Path.GetFileName(path));
return File(_buffer, "application/png");
}
return View("Error");
}
I call it like this:
Real Time Update
As you can see, I have target="_blank", however, instead of displaying the image in a new tab, it downloads it to my documents folder. How can I get it to display in a tab?
You need a ImageController to render that.
once you have a controller you can render as follows:
public class ImageController{
public ActionResult ShowImage(string path)
{
return File(path);
}
}
in your views:
<img src="#Url.Action("Render","Image", new {id =1 // or path })" />
this answer was taken from https://stackoverflow.com/a/16142574/5586581

ASP.NET MVC Controller cannot return HttpResponseMessage correctly with streamed content

Just as the title says I am not getting the MVC Controller to return HttpResponseMessage correctly.
[HttpGet]
[AllowAnonymous]
public HttpResponseMessage GetDataAsJsonStream()
{
object returnObj = new
{
Name = "Alice",
Age = 23,
Pets = new List<string> { "Fido", "Polly", "Spot" }
};
var response = Request.CreateResponse(HttpStatusCode.OK);
var stream = new MemoryStream().SerializeJson(returnObj);
stream.Position = 0;
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return response;
}
This is what I got using MVC Controller:
It works fine when using WebApi ApiController
Correct me if I'm wrong I think the problem is MVC is serializing HttpResponseMessage instead of returning it.
By the way I am using MVC 5.
Thanks in advance.
EDIT
I would like to have the flexibility to write to the response stream directly when returning large datasets.
Perhaps try returning an ActionResult from your MVC method instead.
public ActionResult GetDataAsJsonStream() {}
In order to return a stream, you'll likely have to use FileStreamResult. What would be even easier is just returning a JsonResult.
public ActionResult GetDataAsJson()
{
object returnObj = new
{
Name = "Alice",
Age = 23,
Pets = new List<string> { "Fido", "Polly", "Spot" }
};
return Json(returnObj, JsonRequestBehavior.AllowGet);
}
This is pseudo code but the concept should be sound.
Thanks to Phil I got it to work by having the MVC controller return FileStreamResult.
Here is the code
public ActionResult GetDataAsJsonStream()
{
object returnObj = new
{
Name = "Alice",
Age = 23,
Pets = new List<string> { "Fido", "Polly", "Spot" }
};
var stream = new MemoryStream().SerializeJson(returnObj);
stream.Position = 0;
return File(stream, "application/json");
}
UPDATE
A better way to do this is to write directly to the response stream without creating a memory stream
public ActionResult GetJsonStreamWrittenToResponseStream()
{
object returnObj = new
{
Name = "Alice",
Age = 23,
Pets = new List<string> { "Fido", "Polly", "Spot" }
};
Response.ContentType = "application/json";
Response.OutputStream.SerializeJson(returnObj);
return new EmptyResult();
}

Troubleshoot MVC model binding failure - argument is null in controller

I am trying to POST an object from a WebJob to an MVC 4 controller. I am using Entity Framework. In the controller, I cannot get the object to bind properly (the argument is null). I have looked at many tutorials and it seems like my code should work.
Model (does this need to be in a specific namespace for EF to find it?):
public class CreateListingObject
{
public Listing listing;
public List<GalleryImage> images;
public CreateListingObject()
{
listing = new Listing();
images = new List<GalleryImage>();
}
}
public struct GalleryImage
{
public string picURL;
public string caption;
}
POST:
public void PostListing(CreateListingObject o)
{
Console.WriteLine("Posting listing: {0}", o.listing.Title);
HttpClient _httpClient = new HttpClient();
Uri uri = new Uri(_serviceUri, "/Automaton/CreateTestListing");
string json = BizbotHelper.SerializeJson(o);
HttpResponseMessage response = BizbotHelper.SendRequest(_httpClient, HttpMethod.Post, uri, json);
string r = response.Content.ReadAsStringAsync().Result;
response.EnsureSuccessStatusCode();
}
SendRequest (thank you Azure search samples):
public static HttpResponseMessage SendRequest(HttpClient client, HttpMethod method, Uri uri, string json = null)
{
UriBuilder builder = new UriBuilder(uri);
//string separator = string.IsNullOrWhiteSpace(builder.Query) ? string.Empty : "&";
//builder.Query = builder.Query.TrimStart('?') + separator + ApiVersionString;
var request = new HttpRequestMessage(method, builder.Uri);
if (json != null)
{
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
}
return client.SendAsync(request).Result;
}
Controller Action fragment (o is an empty object here):
[HttpPost]
public ActionResult CreateTestListing(CreateListingObject o)
{
Listing li = o.listing;
I have confirmed that if I post a simple object using the same code, everything works as expected.
Instead of sending a CreateListingObject in PostListing, I send this instead:
var test = new
{
data = "hi mom"
};
And change my action to, then the argument gets bound and I get valid data:
[HttpPost]
public ActionResult CreateTestListing(string data)
{
I have also checked the serialization of my CreateListingObject in the WebJob, and it is fully populated as I expect. This leads me to suspect that I am falling afoul of the default ModelBinder.

Passing viewmodel from one method to another (post)

I have a wizardtype form where i would like to keep the model from the first step to the last.
This is how im doing it now, but i cant seem to keep the model from step 3 to 4.
[HttpPost]
public ActionResult Register(MemberViewModel model)
{
var mobile = model.Mobile;
var xml = MemberclubHelper.CreateVerificationTokenXML(mobile, "47");
MemberclubHelper.SendVerificationToken(xml);
return RedirectToAction("RegisterStep1", new { mobile = mobile });
}
public ActionResult RegisterStep1(string mobile)
{
var model = new MemberViewModel();
model.Mobile = mobile;
return View("Register/Step1", model);
}
[HttpPost]
public ActionResult RegisterStep1(MemberViewModel model)
{
var interests = (from interest in model.Interests where interest.isChecked select interest.value).ToList();
var passing = (from pass in model.Passing where pass.isChecked select pass.value).ToList();
var xml = MemberclubHelper.CreateMemberProfileXML(model.Mobile, model.FirstName, model.FirstName,
model.Email1, model.Zipcode, model.SelectedKid1, model.SelectedKid2, model.SelectedKid3,
model.Gender.ToString(), interests, passing);
model.XmlToSend = xml;
if (xml.Contains("error"))
{
model.ErrorMessage = xml;
return View("Register/Step1", model);
}
return View("Register/Step2", model);
}
[HttpPost]
public ActionResult RegisterStep2(MemberViewModel model)
{
var result = MemberclubHelper.SendCreateUser(model.XmlToSend, model.Password);
if (result.Contains("error"))
{
model.ErrorMessage = result;
return View("Register/Step2", model);
}
else
{
return View("Register/Finished");
}
}
I think you may be better served by creating a separate view model for each step (i.e., MemberViewModelStep1). To me this seems like only some of your MemberViewModel properties will will be set in each step unless you carry a lot of that state between steps via hidden inputs or some other mechanism.
Alternatively, have you considered using JavaScript to build up that state between across your steps and then submitting a single post with your fully populated MemberViewModel?

Read image from database and display in view

I'm trying to convert an older ASP.NET application to MVC (I am just learning MVC). and I have a need to display an image in a Gridview. The image itself is stored in a SQL Server table as datatype image. The code that was used previously is below. Can someone suggest an approach using MVC? I was thinking of creating a partial page that I could embed in a standard view, but not sure if that is the right design to implement.
Thanks is advance!
` string sqlText = "SELECT * FROM Images WHERE img_pk = " + id;
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString);
SqlCommand command = new SqlCommand(sqlText, connection);
connection.Open();
SqlDataReader dr = command.ExecuteReader();
if (dr.Read())
{
//Response.Write("test");
Response.BinaryWrite((byte[])dr["img_data"]);
}
connection.Close();
}
Then it can be referenced using this image tag:
<asp:Image Height="73" Width="80" ID="Image1" ImageAlign="Middle" ImageUrl='<%#"viewimage.aspx?id=" + Eval("ImageId") %>' runat="server"/></a></td>
The first thing is to forget about GridView in an ASP.NET MVC application. Server side controls, postbacks, viewstate, events, ... all those are notions that no longer exists.
In ASP.NET MVC you work with Models, Controllers and Views.
So you could write a controller action which will fetch the image from the database and serve it:
public class ImagesController: Controller
{
public ActionResult Index(int id)
{
string sqlText = "SELECT img_data FROM Images WHERE img_pk = #id";
using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString))
using (var command = conn.CreateCommand())
{
conn.Open();
command.CommandText = sqlText;
command.Parameters.AddWithValue("#id", id);
using (var reader = command.ExecuteReader())
{
if (!reader.Read())
{
return HttpNotFound();
}
var data = GetBytes(reader, reader.GetOrdinal("img_data"));
return File(data, "image/jpg");
}
}
}
private byte[] GetBytes(IDataReader reader, int columnIndex)
{
const int CHUNK_SIZE = 2 * 1024;
byte[] buffer = new byte[CHUNK_SIZE];
long bytesRead;
long fieldOffset = 0;
using (var stream = new MemoryStream())
{
while ((bytesRead = reader.GetBytes(columnIndex, fieldOffset, buffer, 0, buffer.Length)) > 0)
{
byte[] actualRead = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, actualRead, 0, (int)bytesRead);
stream.Write(actualRead, 0, actualRead.Length);
fieldOffset += bytesRead;
}
return stream.ToArray();
}
}
}
and then in your view simply:
<img src="#Url.Action("Index", "Images", new { id = "123" })" alt="" />
Now of course all this controller action is nice and dandy, but you should really abstract all data access into a repository:
public interface IImagesRepository
{
byte[] GetImageData(int id);
}
then implement this method for the data provider you are using:
public class ImagesRepositorySql: IImagesRepository
{
public byte[] GetImageData(int id)
{
// you already know what to do here.
throw new NotImplementedException();
}
}
Finally you will have your controller become database agnostic. Layers in your application are now weakly coupled between them which would allow you to reuse and unit test them in isolation:
public class ImagesController: Controller
{
private readonly IImagesRepository _repository;
public ImagesController(IImagesRepository repository)
{
_repository = repository;
}
public ActionResult Index(int id)
{
var data = _repository.GetImageData(id);
return File(data, "image/jpg");
}
}
and the last part would be to configure your favorite DI framework to inject the proper implementation of the repository into the controller.

Resources