Serve image through ajax in html helper - c#

I am curios about a thing. Let's say I am saving images in a SQL Database ( I know it's not recommended; the best way it's to save only a reference to a image saved somewhere else, but I want to ask you something about this specific case ).
I am serving a file like this :
public ActionResult Serve(int id)
{
......
return File(img.Content, img.ContentType);
}
I have also made an Html helper :
public static HtmlString ServeImage(this HtmlHelper html, int id)
{
var urlHelper= new UrlHelper(html.ViewContext.RequestContext);
var tag= "<img src='{0}' width='200' height='200' />";
return new HtmlString(string.Format(imageTag, urlHelper.Action("Serve", "Image", new { id = id })));
}
So, when I want to show a picture I am writing in a view something like this: #Html.ServeImage(imageId)
My question is: *Is there any way yo call urlHelper.Action("Serve", "Image", new { id = id }))) through ajax and still use my helper? *
I have read about Ajax Helpers but I think it doesn't help me here and I have only one option left. I need to give up my helper and call my action with ajax like I normally do. Is this right?
I mean:
$.ajax(function() {
.....
});

You can just use a plain img tag and set the src to #urlHelper.Action("Serve", "Image", new { id = id })))
Example:
<img src='#urlHelper.Action("Serve", "Image", new { id = id })' width='200' height='200' />

Related

How to generate a link to a html page with parameters WebApi

I'm trying to create a ResetPassword Page and I need to create something like that!
myApi.azure.com/ResetPassword?hash=YYYYYYYYYYYYYY
I already know how to create a link to another controller, but that way it would trigger the Action just with the click, and what I need is pass the hash as parameter inside of that URL and them, call a controller!
var link = new Uri(Url.Link("ValidationEmailUser", new { Code = emailToken }));
Something like this:
public IHttpActionResult RedirectAction()
{
var urlFormat = string.Format("https://www3.olx.com.br/account/forgotten_password/?hash={0}", emailToken);
var location = new Uri(urlFormat);
return this.Redirect(location);
}

How to get byte[] to display as a background image for a div on a view (C#, ASP.NET, MVC)

I am building a web app in C# and ASP.Net with an MVC framework. I have the app running on my local desktop (for now). The app has a SQL backend that stores all my data. I am able to pull the data from the SQL db successfully through a number of stored procedures. The data is able to successfully be transferred from the stored procedures all the way up to my view from the controller.
Part of the data being transferred to the view is a byte[] from an image stored in the db (datatype is VARBINARY(MAX)). In short, I am trying to get the data from this byte[] to display as a background image in a div. This div acts as a single image in a Bootstrap carousel.
Initially, I had the following as my controller:
public ActionResult Dashboard()
{
DashboardViewModelHolder holder = new DashboardViewModelHolder();
DiscoveryService discoveryService = new DiscoveryService();
holder.national_Elected_Officials = new List<National_Elected_Officials_Model>();
National_Elected_Officials_Model n = new National_Elected_Officials_Model();
foreach (List<object> official in discoveryService.retrieve_National_Elected_Officials())
{
for(int i = 0; i <= official.Count; i++)
{
int id = int.Parse(official.ElementAt(0).ToString());
string fname = official.ElementAt(1).ToString();
string lname = official.ElementAt(2).ToString();
byte[] pictureByteArray = (byte[])official.ElementAt(3);
string position = official.ElementAt(4).ToString();
string party = official.ElementAt(5).ToString();
string bio = official.ElementAt(6).ToString();
int yearsOfService = int.Parse(official.ElementAt(7).ToString());
int terms = int.Parse(official.ElementAt(8).ToString());
string branch = official.ElementAt(9).ToString();
Image picture = image_Adapter.byteArrayToImage(pictureByteArray);
n.ElectedOfficialID = id;
n.FirstName = fname;
n.LastName = lname;
n.Picture = picture;
n.Position = position;
n.Party = party;
n.Bio = bio;
n.YearsOfService = yearsOfService;
n.Terms = terms;
n.Branch = branch;
}
holder.national_Elected_Officials.Add(n);
}
return View(holder);
}
My thought process was that I would just call n.Picture in my view and it would render the picture. After several tries and tutorials later, I left n.Picture as a byte[] and processed it in its own ActionResult method as seen below:
public FileContentResult Image(byte[] pictureByteArray)
{
return new FileContentResult(pictureByteArray, "image/jpeg");
}
I call this in my view as the following:
<div class="fill" style="background-image:src(#Url.Action("Image", electedOfficial.Picture))"></div>
electedOfficial is a reference to the model being set in the controller (n.Picture).
Is there something that I am missing?
EDIT 1
I forgot to add that the div returns null when I debug and step through the code. This is because the line with the div never gets called on when debugging. If I have it set as Url.Action, the program will actually go to the controller before hitting the line. If I do Html.Action, the program will skip the line and go to the controller after. Both will return null as a result which returns an error on the controller side since nulls arent allowed.
Edit 2
I tried changing the div tag to the following:
<div class="fill" style="background-image:src(#{Html.Action("Image", electedOfficial.Picture);})"></div>
By putting the {} in the debugger actually parses the line as I step through. Now, the problem is that the controller is not receiving the value being passed to it from electedOfficial.Picture. Just to confirm, this variable does hold the correct value in the view.
If you have the full byte[] in your model, then you can put the data directly into the view:
<div style="background:url( data:image/jpeg;base64,#Convert.ToBase64String(electedOfficial.Picture) )"></div>
This will work without the need for a separate controller that returns a FileContentResult, but will be a longer initial page load since the user will download all of the images along with the page HTML.
If you want to use a Controller endpoint so the images can be referenced as a URL in the src attribute and downloaded after the HTML has rendered then you are not too far off. It would work better to have the controller accept ElectedOfficialID and return the FileContentResult from that.
public FileContentResult Image(int electedOfficialId)
{
byte[] picture = GetPicture(electedOfficialId);
return new FileContentResult(picture, "image/jpeg");
}
Simples way of doing that would be encoding image as base64 string and add new string property eg PictureAsString to model instead having Picture
controller
n.PictureAsString = Convert.ToBase64String(pictureByteArray)
view
<div style="background:url(data:image/jpeg;base64,#electedOfficial.PictureAsString )" ></div>
use handler(ASHX). and call handler url in src.
public class MyHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
//Get Id from somewhere
//Get binary data
context.Response.ContentType = "application/octet-stream";
context.Response.BinaryWrite(bytes);
}
}
You can convert your byte array into a picture using this way:
Convert your byte array into a base64 string.
Display it in <img> tag.
Here is the code:
#{
var base64 = Convert.ToBase64String(Model.ByteArray);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
}
<img src="#imgSrc" />

Extending HtmlHelper RouteLink

I've been bashing my head for a quite some time now and I'm pretty sure I'm missing something very obvious. I want to create a route link, that can dynamically set css class to "selected", if the current controller action matches it. It's easy, however, I'm having troubles modifying existing htmlAttributes that I need to pass in.
public static MvcHtmlString RouteLinkSelectable(this HtmlHelper html, string linkText, string routeName, object routeValues, object htmlAttributes, string controller = null, string action = null)
{
// omitting code for determining if the class should be set, because it
// doesn't modify the behavior. It does that same thing with the following code
var myAttributes = new Dictionary<string, object>
{
{ "data-myattribute1", "value1" },
{ "data-myattribute2", "value2" }
};
var attributes = new RouteValueDictionary(htmlAttributes);
// now merge them with the user attributes
foreach (var item in attributes)
{
// remove this test if you want to overwrite existing keys
if (!myAttributes.ContainsKey(item.Key))
{
myAttributes[item.Key] = item.Value;
}
}
return html.RouteLink(linkText, routeName, routeValues, myAttributes);
}
This is the code (well one of the variations I've been trying) that was suggested by Darin Dimitrov in this answer https://stackoverflow.com/a/12729240/1289283
That should work, right? Well, not exactly..
When I call it from my layout like this:
#Html.RouteLinkSelectable("profil", "Default", null, new { id = "lnkProfile" }, action: "Index")
It produces this output:
<a Comparer="System.Collections.Generic.GenericEqualityComparer`1[System.String]" Count="3" Keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" Values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]" href="/">profil</a>
If I modify the code to use classical syntax (...., new { id = "lnkProfile" }), it works good. If I create a new class with properties, it works good. If I use expando object, it doesn't attach any html properties... And if try to use a dictionary, the result is shown above... Please, can anyone explain it to me, why does it behave like this and how can I solve that?
Btw, of course I could create a link from scratch, but why reinvent the wheel when I simply need just to add one html attribute dynamically?
The problem is that you are targeting the wrong overload of RouteLink, change the return statement with the following
return html.RouteLink(linkText, routeName, new RouteValueDictionary(routeValues), myAttributes);

How to return multiple images from controller method?

I have an ASP.NET MVC controller that generates images (they are stored in memory, I don't want to store them on the hard drive) and should return them to my view.
The problem is: I don't how know how to return multiple images from one controller method (I want to show the images in 1 view). I know that I can return a single image with the FileResult for example, but I can't find out (not on google/stackoverflow) how to return multiple images from the same method. Splitting the method up in multiple methods can't be done. Oh, all of the images are converted to a byte[], but that can be reversed if necessary.
This should work. Note I am reading my images from disk for my example but they can come from memory or anywhere. Then on the client side use java-script to display them.
[HttpGet]
public JsonResult Images()
{
var image1Base64 = Convert.ToBase64String(System.IO.File.ReadAllBytes(Server.MapPath("~/Images/1.jpg")));
var image2Base64 = Convert.ToBase64String(System.IO.File.ReadAllBytes(Server.MapPath("~/Images/2.jpg")));
var jsonResult = Json(new { image1 = image1Base64, image2 = image2Base64 }, JsonRequestBehavior.AllowGet);
jsonResult.MaxJsonLength = int.MaxValue;
return jsonResult;
}
If you have access to the MIME type of the image, you could always render them as Base64-encoded images, instead of making another request to a different controller method. This is a view model I use:
public class ImageViewModel
{
public string FileName { get; set; }
public string MIME { get; set; }
public byte[] Data { get; set; }
public override string ToString()
{
return string.Format(#"data:{0};base64,{1}", MIME.ToLower(), Convert.ToBase64String(Data));
}
}
You can use the Filename property in the alt attribute of the <img /> tag, so the markup & model-binding in your view would look something like this (assuming Razor syntax):
<img src="#model.ToString()" alt="#model.FileName" />
You do lose image-caching, AFAIK - that hasn't been an issue for me, but is understandably a deal-breaker for some.
I think that you can solve it in another way, instead of returning multiple images, you can create a utility method that loads the image in the controller
public FileContentResult GetImage(int imageId)
{
var image = GetImageById(imageId); // get from a list for example
return File(image, "image/jpeg"); // your image Mime type
}
and in the View you can do the following, iterate over the images
#foreach (var image in Model)
{
<img alt="" src="#Url.Action("GetImage", "ControllerName", new {imageId =image.Id})"/>
}
You wish to show multiple images based on input of the user, but don't want to save to the hard disk (chat). Therefor I recommand you using a session variable to save the users input in. And the use a simple FileResult to return multiple images based on that session variable.
http://blog.theobjectguy.com/2009/12/session-with-style.html
If your requirement is to show multiple images in one view it would be easier to use 2 action methods. One that returns a image with FileResult and another where you just use standard html img tags pointing the first action method

How to use MVC 3 #Html.ActionLink inside c# code

I want to call the #Html.ActionLink method inside a c# function to return a string with a link on it.
Something like this:
string a = "Email is locked, click " + #Html.ActionLink("here to unlock.", "unlock") ;
Assuming that you want to accomplish this in your controller, there are several hoops to jump through. You must instantiate a ViewDataDictionary and a TempDataDictionary. Then you need to take the ControllerContext and create an IView. Finally, you are ready to create your HtmlHelper using all of these elements (plus your RouteCollection).
Once you have done all of this, you can use LinkExtensions.ActionLink to create your custom link. In your view, you will need to use #Html.Raw() to display your links, to prevent them from being HTML encoded. Here is the necessary code:
var vdd = new ViewDataDictionary();
var tdd = new TempDataDictionary();
var controllerContext = this.ControllerContext;
var view = new RazorView(controllerContext, "/", "/", false, null);
var html = new HtmlHelper(new ViewContext(controllerContext, view, vdd, tdd, new StringWriter()),
new ViewDataContainer(vdd), RouteTable.Routes);
var a = "Email is locked, click " + LinkExtensions.ActionLink(html, "here to unlock.", "unlock", "controller").ToString();
Having shown all of this, I will caution you that it is a much better idea to do this in your view. Add the error and other information to your ViewModel, then code your view to create the link. If this is needed across multiple views, create an HtmlHelper to do the link creation.
UPDATE
To address one.beat.consumer, my initial answer was an example of what is possible. If the developer needs to reuse this technique, the complexity can be hidden in a static helper, like so:
public static class ControllerHtml
{
// this class from internal TemplateHelpers class in System.Web.Mvc namespace
private class ViewDataContainer : IViewDataContainer
{
public ViewDataContainer(ViewDataDictionary viewData)
{
ViewData = viewData;
}
public ViewDataDictionary ViewData { get; set; }
}
private static HtmlHelper htmlHelper;
public static HtmlHelper Html(Controller controller)
{
if (htmlHelper == null)
{
var vdd = new ViewDataDictionary();
var tdd = new TempDataDictionary();
var controllerContext = controller.ControllerContext;
var view = new RazorView(controllerContext, "/", "/", false, null);
htmlHelper = new HtmlHelper(new ViewContext(controllerContext, view, vdd, tdd, new StringWriter()),
new ViewDataContainer(vdd), RouteTable.Routes);
}
return htmlHelper;
}
public static HtmlHelper Html(Controller controller, object model)
{
if (htmlHelper == null || htmlHelper.ViewData.Model == null || !htmlHelper.ViewData.Model.Equals(model))
{
var vdd = new ViewDataDictionary();
vdd.Model = model;
var tdd = new TempDataDictionary();
var controllerContext = controller.ControllerContext;
var view = new RazorView(controllerContext, "/", "/", false, null);
htmlHelper = new HtmlHelper(new ViewContext(controllerContext, view, vdd, tdd, new StringWriter()),
new ViewDataContainer(vdd), RouteTable.Routes);
}
return htmlHelper;
}
}
Then, in a controller, it is used like so:
var a = "Email is locked, click " +
ControllerHtml.Html(this).ActionLink("here to unlock.", "unlock", "controller").ToString();
or like so:
var model = new MyModel();
var text = ControllerHtml.Html(this, model).EditorForModel();
While it is easier to use Url.Action, this now extends into a powerful tool to generate any mark-up within a controller using all of the HtmlHelpers (with full Intellisense).
Possibilities of use include generating mark-up using models and Editor templates for emails, pdf generation, on-line document delivery, etc.
You could create an HtmlHelper extension method:
public static string GetUnlockText(this HtmlHelper helper)
{
string a = "Email is locked, click " + helper.ActionLink("here to unlock.", "unlock");
return a;
}
or if you mean to generate this link outside of the scope of an aspx page you'll need to create a reference to an HtmlHelper and then generate. I do this in a UrlUtility static class (I know, people hate static classes and the word Utility, but try to focus). Overload as necessary:
public static string ActionLink(string linkText, string actionName, string controllerName)
{
var httpContext = new HttpContextWrapper(System.Web.HttpContext.Current);
var requestContext = new RequestContext(httpContext, new RouteData());
var urlHelper = new UrlHelper(requestContext);
return urlHelper.ActionLink(linkText, actionName, controllerName, null);
}
Then you can write the following from wherever your heart desires:
string a = "Email is locked, click " + UrlUtility.ActionLink("here to unlock.", "unlock", "controller");
There's a couple things bad about these other answers...
Shark's answer requires you to bring the LinkExtensions namespace into C#, which is not wrong, but undesirable to me.
Hunter's idea of making a helper is a better one, but still writing a helper function for a single URL is cumbersome. You could write a helper to help you build strings that accepted parameters, or you could simply do it the old fashion way:
var link = "Email is... click, to unlock.";
#counsellorben,
i see no reason for the complexity; the user wants only to render an Action's routing into a hard string containing an anchor tag. Moreover, ActionLink() in a hard-written concatenated string buys one nothing, and forces the developer to use LinkExtensions whidh are intended for Views.
If the user is diehard about using ActionLink() or does not need (for some reason) to calculate this string in the constructor, doing so in a view is much better.
I still stand by and recommend the answers tvanfosson and I provided.
Your best bet is to construct the link manually using the UrlHelper available in the controller. Having said that, I'm suspicious that there is probably a better way to handle this in a view or partial view, shared or otherwise.
string a = "Email is locked, click <a href=\""
+ Url.Action( "unlock" )
+ "\">here to unlock.</a>";
Maybe try this:
string a = "Email is locked, click " + System.Web.Mvc.Html.LinkExtensions.ActionLink("here to unlock.", "unlock");

Categories