I'm having a bit of a brain fart; it must be Monday...
I have an MVC form, which allow the user to submit an image.
The image is saved to a folder, then I want to redirect to another Controller and Action to display the image.
What are my options for passing the image name and path back to the controller action to display the graphic?
// Handles the updload, contains a control (ascx)
// and the control's action method is in another controller
public ActionResult Index()
{
return View();
}
// I want this page to display the image uploaded in the Upload.ascx control
// that is in the index method above:
public ActionResult Result()
{
ViewData["MyImage"] = ???
}
Thanks much.
Where is the image being stored? In your content area or in a database? If it's in a database, then I'd construct the controller/action url to display that image form the db. If it's in your content area, then you can construct the url based on the name of the uploaded file. I'd probably create a model rather than passing the url in view data, but view data is a valid (i.e., it works) alternative.
public ActionResult Result( int id ) // db storage
{
return View( new UploadModel
{
ImageUrl = Url.Action( "display", "image", new { id = id }
} );
}
public ActionResult Result() // content area
{
var imageName = ... get image name from ??? ...
return View( new UploadModel
{
ImageUrl = Url.Content( "~/content/images/uploads/" + iamgeName );
});
}
Related
How can I get both the image and tooltip in a single call to a MVC controller method? I can use something like the following to get the image, but how to also get the associated tooltip? The use case is to display an image if the user is allowed to see the image, else display a generic image and a tooltip indicating why the image is not being shown.
To clarify, I would like to avoid two calls to the controller, once to get the image path and tooltip, and another to get the image file. Not only will this result in two round trips across the network, it would also repeat the validation checks. The problem is that the img src call only accommodates the image, not other properties such as the title associated with the image.
<img src="#Url.Action("GetPicture", "User", new { userId = Model.User.Id })" />
Can't you just have a second method for GetTitle using the same permission logic from GetImage and return the appropriate text for each user? Then call this method for the title attribute.
Can you approach the problem in the following way.
Create Model
public class ImageViewModel
{
public string ImagePath
{
get;
set;
}
public string ImageTitle
{
get;
set;
}
}
Create a partial View
#using StackOverFlowProject.Models
#model ImageViewModel
<img src=#Model.ImagePath title=#Model.ImageTitle />
Your Controller
public PartialViewResult _Image(string userID)
{
ImageViewModel model = new ImageViewModel();
//Here You can check what image and tooltip you want show to the user
//model = //FillData from DB /
return PartialView("_Image", model);
}
and at last in Your MainView where you want to display the Image render the partial view
Not sure if this is the best way to do it, but I did it by creating an Ajax form, submitting it using jQuery, returning a JSON object with the byte array encoded as a Base64 string, and using Javascript to display the image. Seems to be working so far, will know more from further tests.
In the view:
<div id="imgDiv">
#using (Ajax.BeginForm("GetImg", "User", null, new AjaxOptions()
{
HttpMethod = "POST",
Url = Url.Action("GetImg", "User"),
OnSuccess = "DisplayImageWithTooltip(data, 'imgDiv')",
}, new { id = "ImgForm", #class = "imageGetterWithTooltip" }))
{
#Html.AntiForgeryToken()
#Html.Hidden("userId", #Model.User.Id)
}
</div>
Javascript to submit form:
$(".imageGetterWithTooltip").submit();
In Controller (based on https://stackoverflow.com/a/9464137/1385857)
return Json(new
{
fileBytes = Convert.ToBase64String(<File byte[]>),
fileType = <FileType>,
tooltip = <toolTip>
}, JsonRequestBehavior.AllowGet);
Javascript to display image
function DisplayImageWithTooltip(data, target) {
var oImg = document.createElement("img");
oImg.width = 150;
oImg.height = 150;
oImg.setAttribute('src', "data:" + data.fileType + ";base64," + data.fileBytes);
oImg.setAttribute('title', data.tooltip);
document.getElementById(target).appendChild(oImg);
}
Using Manish's ideas, my simplified solution is to create a partial view and supply it the image data directly:
Controller:
vmMiniData data = new Models.vmMiniData();
byte[] byteArray = Users.GetPersonnelImage(personnelID);
if (byteArray != null)
{
data.ImageStr = Convert.ToBase64String(byteArray);
}
else
{
data.ImageStr = Convert.ToBase64String(Users.GetPersonnelImage("00000000-0000-0000-0000-000000000000")); //get blank image
}
data.CaptionStr = Users.GetUserJobTitle(personnelID);
return PartialView("Personnel/MiniPersonnelPartial", data);
Model:
public static byte[] GetPersonnelImage(string personnelID)
{
byte[] img = (byte[])(from record in db.PersonnelImages
.Where(R => R.PersonnelID == new Guid(personnelID))
select record.Image).FirstOrDefault();
return img;
}
Then in the partial:
#model vmMiniData
<div>
<div>#Model.CaptionStr</div>
<div> <img src="data:image;base64,#Model.ImageStr" style="width:60px;min-height:30px;" /></div>
</div>
It works very well in MVC 5 :).
i have a view to display the information of a specific model.
in that information i have an image, which is a byte of array.
now i want to display that image.
i make this in my view
<img src="#Url.Action("getImg", "Image", new { image = Model.image })" />
note that the Image controller is not the same controller that the current view belong to
what am i getting wrong please?
all the other imformation are displayed correctly.
Edit
this is the controller that i want to call
public class ImageController : Controller
{
//
// GET: /Image/
public ActionResult Index()
{
return HttpNotFound();
}
// To convert the Byte Array to the image
public FileContentResult getImg(byte[] image)
{
if (image != null)
{
return new FileContentResult(image, "image/jpeg");
}
else
{
return null;
}
}
}
This appears to be a very poor choice in design. This code:
<img src="#Url.Action("getImg", "Image", new { image = Model.image })" />
So the image will be sent as a byte array to the client (lets say 60,000 bytes). Will create html that might look like:
<img src="/Image/getImg/?image=bc15b2c53... (lots of characters" />
This html is really long, basically sending the image as a byte array to the client. Next the browser will make another request to get the image by sending the byte array back to the controller (another 60,000 bytes to the server).
Next, the controller will return the byte array sent to it back again to the browser, as an image. Three trips of 60k of data is a terrible idea.
Update
The better way to do this is to not send the bytes array to the view, but an ID.
<img src="#Url.Action("getImg", "Image", new { id = Model.id })" />
Then in the controller:
public class ImageController : Controller
{
public FileContentResult getImg(int?/guid? id)
{
if (id.HasValue)
{
byte[] bytes = db.GetBytesById(id.Value);
return new FileContentResult(bytes, "image/jpeg");
}
else
{
// be nice to the browser, send the correct result!
return new FileNotFoundResult();
}
}
}
the code in view which i am dispalying using foreach loop
#Url.Action("StartJob", "Batch", new { batchName = #Model.BatchInformationList.ElementAt(i-1).JobName })
the code in controller
public PartialViewResult StartJob(string batchName)
{
return this.PartialView(res);
}
I am getting data in batchname of last element in the model I am iterating
Hi you can use this,
#Html.ActionLink("EditUser","StartJob", "Batch",new { batchName = #Model.BatchInformationList.ElementAt(i-1).JobName })
in ActionLink First paramete is string, second is your page likeStartJob, third is controllerBatch. And this directly redirect to your action.
Controller
public ActionResult StartJob(string batchName )
{
return this.PartialView(res);
}
On my asp.net mvc page I need to render multiple images that are stored on third-party images hosting service. The service has some api which returns me a list of image urls.
In *.cshtml file a have the fallowing html markup:
#foreach (var img in Model.Images)
{
<img src="#img.ImageUrl" />
}
It's works perfectly. But for some reason I can't use direct URL to the image in the "src" attribute. Next, I have created new async controller that should return an image:
public class ImagesController : AsyncController
{
//
// GET: /Images/
public void GetImageAsync(string url)
{
AsyncManager.OutstandingOperations.Increment();
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
AsyncManager.Parameters["response"] = response;
AsyncManager.OutstandingOperations.Decrement();
}
public FileResult GetImageCompleted(WebResponse response)
{
return base.File(response.GetResponseStream(), response.ContentType);
}
}
Now I need to pass a full image url to my controller action.
Something like this:
#foreach (var img in Model.Images)
{
<img src="Images/GetImage/**#img.ImageUrl**" />
}
how to create a new route for passing this parameter to action?
Thanks!
You mean this?
routes.MapRoute(
"GetImage",
"Images/GetImage/{*url}",
new { controller = "Images", action = "GetImageAsync" }
);
I'm not sure why you need all that though. An AsyncController + routing in order to fetch all image url's seems to be overkill...
I currently have the following code for the POST to edit a customer note.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditNote(Note note)
{
if (ValidateNote(note))
{
_customerRepository.Save(note);
return RedirectToAction("Notes", "Customers", new { id = note.CustomerID.ToString() });
}
else
{
var _customer = _customerRepository.GetCustomer(new Customer() { CustomerID = Convert.ToInt32(note.CustomerID) });
var _notePriorities = _customerRepository.GetNotePriorities(new Paging(), new NotePriority() { NotePriorityActive = true });
IEnumerable<SelectListItem> _selectNotePriorities = from c in _notePriorities
select new SelectListItem
{
Text = c.NotePriorityName,
Value = c.NotePriorityID.ToString()
};
var viewState = new GenericViewState
{
Customer = _customer,
SelectNotePriorities = _selectNotePriorities
};
return View(viewState);
}
}
If Validation fails, I want it to render the EditNote view again but preserve the url parameters (NoteID and CustomerID) for something like this: "http://localhost:63137/Customers/EditNote/?NoteID=7&CustomerID=28"
Any ideas on how to accomplish this?
Thanks!
This action is hit by using a post. Wouldn't you want the params to come through as part of the form rather than in the url?
If you do want it, I suppose you could do a RedirectToAction to the edit GET action which contains the noteId and customerId. This would effectively make your action look like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditNote(Note note)
{
if (ValidateNote(note))
{
_customerRepository.Save(note);
return RedirectToAction("Notes", "Customers", new { id = note.CustomerID.ToString() });
}
//It's failed, so do a redirect to action. The EditNote action here would point to the original edit note url.
return RedirectToAction("EditNote", "Customers", new { id = note.CustomerID.ToString() });
}
The benefit of this is that you've removed the need to duplicate your code that gets the customer, notes and wotnot. The downside (although I can't see where it does it here) is that you're not returning validation failures.