mvc4 canot call a function in a controller - asp.net-mvc

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();
}
}
}

Related

Get both image and tooltip in one call

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 :).

ASP.NET MVC - Execute controller action without redirecting

I am trying to execute an action on a controller without redirecting to the associated view for that action. For a good example of what I am trying to achieve take a look at the music.xbox.com website. When you add a song to a selected playlist from a popup menu - the page just shows a notification without any redirect or refresh. how is this possible?
What I have is the following:
I have a _playlistPopupMenu partial view that renders the list of playlists as follows:
_PlaylistPopupMenu
#model List<OneMusic.Models.GetPlaylists_Result>
#if (Model.Count > 0)
{
<li style="height:2px" class="divider"></li>
foreach (var item in Model)
{
<li style="height:30px">#Html.DisplayFor(p => item.Name)
#Html.ActionLink(item.Name, "AddSong", "Playlist", new { playlistId = #item.PlaylistId, songId = 1 }, "")
</li>
}
}
The PlaylistController AddSong action is as follows:
public PartialViewResult AddSong(int? playlistId, int? songId)
{
if (ModelState.IsValid)
{
db.AddSongToPlaylist(playlistId, songId);
db.SaveChanges();
return PartialView("_AddToPlaylist", "");
}
return PartialView("_AddToPlaylist", "");
}
I am struggling with what to put in the _AddToPlaylist partial view which I think I need to be able to display a notification of some kind (Possiblly using PNotify add in for Bootstrap). MVC wants to always redirect to ../Playlist/AddSong?playlistId=1&songId=1
Any ideas on how to complete this last part of the problem would be great.
If you don't want "full page reloads" then you need to approach the problem slightly differently, using javascript to alter the page dynamically. A library such as JQuery might make manipulating the DOM a little easier.
Display the popup dynamically using javascript.
When the user hits OK/Submit on the popup, post the data back to the server using javascript, and have the controller you are posting to return some HTML.
Append the returned HTML block (partial view) to an existing div containing playlist tracks.
The most difficult part of this is the asynchronous post. Help with updating a div without reloading the whole page can be found in this question.
EDIT - Example
If you have a controller action (accepting POSTs) with the URL myapp.com/PlayList/AddSong/, then you'd set up JQuery to post to this URL. You'd also set up the data property with any form data which you'd like to post, in your case you'd add playistId and songId to the data property.
You'd then use the result of the AJAX query (HTML) and append it to the existing playlist HTML on the page. So assuming that you want to append the partial view's HTML to a div with ID playlistDiv, and assuming that your partial view returns HTML which is valid when appended to the existing playlist, then your javascript will look something like this:
var data = { playlistId: 1, songId: 1 };
$.ajax({
type: "POST",
url: 'http://myapp.com/PlayList/AddSong/',
data: data,
success: function(resultData) {
// take the result data and update the div
$("#playlistDiv").append(resultData.html)
},
dataType: dataType
});
Disclaimer: I can't guarantee that this code will work 100% (unless I write the program myself). There may be differences in the version of JQuery that you use, etc, but with a little tweaking it should achieve the desired result.
using System.Web.Mvc;
using System.Web.Mvc.Html;
public ActionResult Index()
{
HtmlHelper helper = new HtmlHelper(new ViewContext(ControllerContext, new WebFormView(ControllerContext, "Index"), new ViewDataDictionary(), new TempDataDictionary(), new System.IO.StringWriter()), new ViewPage());
helper.RenderAction("Index2");
return View();
}
public ActionResult Index2(/*your arg*/)
{
//your code
return new EmptyResult();
}
in your controller you must add bottom code:
public ActionResult Index(string msg)
{
if (Request.Url.ToString().Contains("yourNewExampleUrlWithOutRedirect.com"))
{
string html = "";
using (System.Net.WebClient client = new System.Net.WebClient())
{
client.Encoding = Encoding.UTF8;
html = client.DownloadString("https://NewExampleUrl.com/first/index?id=1");
}
Response.Write(html);
}
...
}
your view must be empty so you add bottom code
#{
ViewBag.Title = "sample title";
if (Request.Url.ToString().Contains("yourNewExampleUrlWithOutRedirect.com"))
{
Layout = null;
}else
{
Layout ="~/Views/Shared/_Layout.cshtml"
}
}
#if (Request.Url.ToString().Contains("yourNewExampleUrlWithOutRedirect.com")==false)
{
before view like :
<div>hello world</div>
}

how to check the file result is null within the mvc view

I have a controller method as below to send an image to a MVC view to display
public FileResult ShowImage(GuidID)
{
DataServiceClient client = new DataServiceClient ();
AdviserImage result;
result = client.GetAdviserImage(ID);
return File(result.Image, "image/jpg" );
}
in my view I am using
<img src="<%= Url.Action("ShowImage", "Adviser", new { ID = Model.AdviserID }) %>" alt="<%:Model.LicenceNumber %>" />
to display the image
but some ids does not have a image and returning null, I want to check the file result is null withing the view and if its null not not to display the image.
You will need another, separate controller action that checks the datastore and returns ContentResult which will be either true or false (or some other string you want to tell whether an ID has the bytes or not) and then in the view you will need this:
if(#Html.Action("action", "controller").ToString().Equals("true", StringComparison.OrdinalIgnoreCase)){
// render image tag with the call to the other action that returns FileResult
}
The other option is that you have a view model which contains a reference to the image bytes. That way you prepare the model for the view (the parent model) in the controller and pull the bytes for the image there, then in the view you would have:
if(Model.ImageBytes.Length() > 0) {
... do something
}
with ImageBytes property being of type byte[]
For instance, this is a snippet from one of my views:
#model pending.Models.Section
#if (Model != null && Model.Image != null && Model.Image.ImageBytes.Count() > 0)
{
<a href="#Model.Url" rel="#Model.Rel">
<img title="#Model.Title" alt="#Model.Title" src="#Url.Action(MVC.Section.Actions.Image(Model.Id))" /></a>
}
HTH
Why not check for null in your controller and leave the logic out of the display:
result = client.GetAdviserImage(ID);
if (result == null)
{
result = AdviserImage.Missing;
}
You can create a default image and make it static. If you really don't want to display the image then create an Html extension method to keep the logic out of the view:
public static string AdviserImage(this HtmlHelper helper, AdviserImage image, int id, int lic)
{
if (image != null)
{
string url = string.Format("/Adviser/ShowImage/{0}", id);
string html = string.Format("<img src=\"{0}\" alt=\"{1}\" />", url, image.lic);
return html;
}
return string.Empty; // or other suitable html element
}

Passing an url as parameter to controller action

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...

ASP.NET MVC Form Submission

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 );
});
}

Resources