Displaying image from db & OutputStream Exceptions ASP.NET/C# - c#

Good night-morning-evening-etc ^_^
I'm getting problems while trying to display an image in asp:Image (using Web Forms), stored in a db as byte[] - found a lot of rather clear answers, how to do it, so now I have a handler:
public class ShowImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
//creating object, working with db
var core = new CoreHolder();
var picture = core.PictureRepository.Read(Convert.ToInt32(context.Request.QueryString["id"]))
context.Response.Clear();
context.Response.ContentType = picture.PictureMimeType;
//trying to write byte[]
context.Response.BinaryWrite(picture.PictureData);
context.Response.End();
}
public bool IsReusable
{
get
{
return false;
}
}
}
...and such strings in my .aspx page:
<asp:Image ID="Image1" runat="server" ImageUrl="~/ShowImageHandler.ashx?id=<%#:Item.ID %>" />
<asp:Image ID="Image1" runat="server" ImageUrl="~/ShowImageHandler.ashx?id=1>" />
The problems are: ok, the program enters the ProcessRequest with id, and in case of the second asp-image string it finds the pic with data, but even before trying to BinaryWrite I can see, that there are exeptions in context.Response.OutputStream: length,position - System.NotSupportedExeption, Read/WriteTimeout - System.InvalidOperationExeption. In case of the first string (it's used in ListView ItemTemplate) the OutputStream problem stays + all crushes on trying to get the id from the query string.
Help, please)

The errors you see in the debugger for context.Response.OutputStream.Length and Position don't matter. You can only write to that stream so the exceptions you see in the debugger display are expected.
Your code looks fine so my guess is that if you look at the URL, the value for your id querystring argument will not be an integer. You are probably getting a FormatException when you try to convert it to an integer.
You should test the handler by putting the url "ShowImageHandler.ashx?id=1" in your browser's address bar instead of using an <img /> tag. That way if there is an exception you can get a real stack trace instead of just seeing a broken image.

Related

asp.net file upload and file reading (Images)

I am using asp.net to create a mobile web application to manage bike parts
I have gotten the file upload working but now I need to figure out how to get an image control to display the image from its new location on a server.
I will be saving the image file path in a database I just need to figure out how to get that new file path for the image.
this is the code I am using for the file upload
if (this.FileUpload1.HasFile)
{
this.FileUpload1.SaveAs(Server.MapPath("~/Mobile/" + FileUpload1.FileName));
}
I can likely figure this out but just in case I can't figured I would post the question now than later as it can take a while to get an answer and I have a dead line
You are going to have to use an "ImageHandler" to read the image properly.
This is how I did my handler.
public class ImageHandler : IHttpHandler
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dboBlog"].ConnectionString);
public void ProcessRequest(HttpContext context)
{
try
{
string messageid = context.Request.QueryString["mid"];
conn.Open();
SqlCommand command = new SqlCommand("SELECT Image from BlogMessages WHERE Image IS NOT NULL AND MessageID=" + messageid, conn);
SqlDataReader dr = command.ExecuteReader();
if (dr.Read())
{
context.Response.BinaryWrite((Byte[])dr[0]);
conn.Close();
context.Response.End();
}
}
catch (Exception ex)
{
return;
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
As you can tell, I use a QueryString. I use this querystring to call the image back. I call my image back in a gridview but this is how it looks...
<asp:Image ID="postImage" runat="server" ImageUrl='<%# "ImageHandler.ashx?mid="+ Eval("MessageID") %>' Width="400px" AlternateText="No Image" ImageAlign="Middle" Visible="false" />
I do set the visibility to false because it's a blog and sometimes people don't upload an image. As you can tell, the image url calls the ImageHandler where the querystring is equal to the MessageID.
This works for me, so hopefully it will help you out.

Variables inside control properties

This code:
<asp:TextBox runat="server" MaxLength="<%=Settings.UsernameMaxLength %>" ID="Username"/>
Throws a parser error.
Is it possible to set properties in any way similar to this without using the code behind?
No, it is not possible. Syntax <%= some code here %> cannot be used with server-side controls. You can either go with <%# some code here %>, but only in case of data binding, or just set this property in code behind, say on Page_Load:
protected void Page_Load(object source, EventArgs e)
{
Username.MaxLength = Settings.UsernameMaxLength;
}
You may try this, which should set the MaxLength value upon rendering :
<%
Username.MaxLength = Settings.UsernameMaxLength;
%>
<asp:TextBox runat="server" ID="Username"/>
I think (not tried) you can also write :
<asp:TextBox runat="server" MaxLength="<%#Settings.UsernameMaxLength %>" ID="Username"/>
But you would then need to call Username.DataBind() somewhere in the codebehind.
I'm late to the party here, but here goes anyway...
You could build your own Expression Builder to handle this case. That would allow you to use syntax like this:
<asp:TextBox
runat="server"
MaxLength="<%$ MySettings: UsernameMaxLength %>"
ID="Username"/>
Note the $ sign.
To learn how to make you own Expression Builder, please go through this old but still relevant tutorial. Don't let the wall of text scare you off because in the end, making an expression builder is easy. It basically consists of deriving a class from System.Web.Compilation.ExpressionBuilder and overriding the GetCodeExpression method. Here is a very simple example (some parts of this code was borrowed from the linked tutorial):
public class SettingsExpressionBuilder : System.Web.Compilation.ExpressionBuilder
{
public override System.CodeDom.CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, System.Web.Compilation.ExpressionBuilderContext context)
{
// here is where the magic happens that tells the compiler
// what to do with the expression it found.
// in this case we return a CodeMethodInvokeExpression that
// makes the compiler insert a call to our custom method
// 'GetValueFromKey'
CodeExpression[] inputParams = new CodeExpression[] {
new CodePrimitiveExpression(entry.Expression.Trim()),
new CodeTypeOfExpression(entry.DeclaringType),
new CodePrimitiveExpression(entry.PropertyInfo.Name)
};
return new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression(
this.GetType()
),
"GetValueFromKey",
inputParams
);
}
public static object GetValueFromKey(string key, Type targetType, string propertyName)
{
// here is where you take the provided key and find the corresponding value to return.
// in this trivial sample, the key itself is returned.
return key;
}
}
In order to use it in your aspx page, you must also register it in web.config:
<configuration>
<system.web>
<compilation ...>
<expressionBuilders>
<add expressionPrefix="MySettings" type="SettingsExpressionBuilder"/>
</expressionBuilders>
</compilation>
</system.web>
</configuration>
This is just to show you that it's not difficult. But please review the tutorial I linked to in order to see an example of how to deal with the expected return type from your method depending on the property being assigned etc.

How do I get the HTML encoding to work in my ASPX page?

I have the following code in an asp Gridvidiew:
<asp:HyperLink ID="hlPSTNNum" CssClass="OrdRef" Text='<%# DataBinder.Eval(Container.DataItem, "PSTNNum")%>' runat="server" ToolTip='please click here to view the full record details'
NavigateUrl='<%#"https://THE URL IS HERE Searches/advancedsearchresults.asp?supplierid=" + Eval("Supplierid") + "&display1=IS%20Number&display2=Supplier&display3=Product&display4=Supplier%20Order%20Number&order1=order%20date&pstnnum=" + Eval("PSTNNum")%>' />
I think Visual Studio 2012 is playing up about the semicolons in the query string part (from "pstnnum=" + Eval("PSTNNum")%>' />" and i tried to escape them with \ (that keeps VS happy), but the browser leaves one of the slashes in at each escape.
Not sure the best practice here as im still cutting my coding teeth...
I think the more appropriate approach would be something like this:
<asp:HyperLink ID="hlPSTNNum"
CssClass="OrdRef"
Text='<%# DataBinder.Eval(Container.DataItem, "PSTNNum")%>'
runat="server"
ToolTip='please click here to view the full record details'
NavigateUrl='<%#Server.HtmlEncode("https://THE URL IS HERE Searches/advancedsearchresults.asp?supplierid=" + Eval("Supplierid") + "&display1=IS Number&display2=Supplier&display3=Product&display4=Supplier Order Number&order1=order date&pstnnum=" + Eval("PSTNNum"))%>' />
Note the use of Server.HtmlEncode and then the use of the actual values you want rather than the directly encoded values. This will make it easy to build in Visual Studio, but ensure it gets encoded when it's rendered.
EDIT
After some more research into Microsoft's code I found that the base RenderContents method for the HyperLink class is going to encode this for you. That method, internally, calls another one called ResolveClientUrl, which looks like this:
public string ResolveClientUrl(string relativeUrl)
{
if (this.DesignMode && this.Page != null && this.Page.Site != null)
{
IUrlResolutionService urlResolutionService = (IUrlResolutionService)this.Page.Site.GetService(typeof(IUrlResolutionService));
if (urlResolutionService != null)
{
return urlResolutionService.ResolveClientUrl(relativeUrl);
}
}
if (relativeUrl == null)
{
throw new ArgumentNullException("relativeUrl");
}
string virtualPathString = VirtualPath.GetVirtualPathString(this.TemplateControlVirtualDirectory);
if (string.IsNullOrEmpty(virtualPathString))
{
return relativeUrl;
}
string text = this.Context.Request.ClientBaseDir.VirtualPathString;
if (!UrlPath.IsAppRelativePath(relativeUrl))
{
if (StringUtil.EqualsIgnoreCase(text, virtualPathString))
{
return relativeUrl;
}
if (relativeUrl.Length == 0 || !UrlPath.IsRelativeUrl(relativeUrl))
{
return relativeUrl;
}
}
string to = UrlPath.Combine(virtualPathString, relativeUrl);
text = UrlPath.AppendSlashToPathIfNeeded(text);
return HttpUtility.UrlPathEncode(UrlPath.MakeRelative(text, to));
}
Since you're URL is not relative it should fall all the way to the last line, the return statement, so honestly you shouldn't have to encode it at all. This changes your code to this:
<asp:HyperLink ID="hlPSTNNum"
CssClass="OrdRef"
Text='<%# DataBinder.Eval(Container.DataItem, "PSTNNum")%>'
runat="server"
ToolTip='please click here to view the full record details'
NavigateUrl='<%#"https://THE URL IS HERE Searches/advancedsearchresults.asp?supplierid=" + Eval("Supplierid") + "&display1=IS Number&display2=Supplier&display3=Product&display4=Supplier Order Number&order1=order date&pstnnum=" + Eval("PSTNNum")%>' />
Not 100% sure if this will work, but asp.net 4.5 has <%#: which encodes automatically. you can try that and see if it works, just change the <%# to <%#:

How do I access a string of a child object on aspx page?

I'm trying to work with a class that has a child object, which has a string - and I'm trying to access this with in-line C# code on my aspx page.
More specifically, let's say I'm working with an object of 'Upload' class which has a Title property (String). An Upload object can also have a 'File' property (object). And each File object has a Url property (String).
I can access the Title like so:
<%# ((Upload)Container.DataItem)["Title"] %>
That works fine. But then how do I access a File's Url? Because the following does not work:
<%# ((File)((Upload)Container.DataItem)["File"]).Url %>
As you may be able to guess from the syntax, this is all within an asp repeater.
try this:
<%# ((Upload)Container.DataItem).File.Url %>
You get the container dataitem & cast it. Once you have the object, you can call it's properties & methods like any other object
you might try something like
<%# Bind("File.Url") %>
or
<%# DataBinder.Eval(Container.DataItem, "File.Url") %>
I am just giving you a sample, you can implmement the same on your own:-
First create a server side code to to return a URL of the File.
Then call that function from client side to get the URL of the title passed to the same.
Below is an example which returns the text with the suffix dots
Step 1 : Create server side code to return text with suffix dots
public string ReturnDotSuffix(string strValue, int iFontSize, int iWidth)
{
string strReturnValue = string.Empty;
try
{
CommonLib objCommonLib = new CommonLib();
strReturnValue = objCommonLib.SuffixDots(strValue, iFontSize, iWidth);
}
catch (Exception ex)
{
HandleException.ExceptionLogging(ex.Source, ex.Message, true);
}
return strReturnValue;
}
Step 2: Call this from Client Side.
Text='<%# ReturnDotSuffix((string)DataBinder.Eval(Container.DataItem, "MessageTitle"),8,170) %>'
The same can be done in your case.

chart.GetHtmlImageMap not working as expected

Gents,
I need help to create an imagemap to my web app's charts. After reading many resources, here and on the web, I end up with the following problem:
The Problem:
On my view I' am calling #Html.Action(RenderMyMap), that renders an <map> tag, with an atribute coords=0,0,0,0.
What Am I doing:
My project is organized this way:
-Core.cs: Class responsable to create the System.Web.UI.DataVisualization.Charting.Chart objects;
-ClientController: With an existing Chart object, I'm saving it with Chat.SaveImage(memoryStream,format), storing it in a session variable as a byte array, and returning a ContentResult object, like in return Content(chart.GetHtmlImageMap());
-ClientController: After that, I'am using the session variable to actually render the chart, like in return File(chartByteArray,"image/png");
-Index.cshtml: Finally in my view I'am calling method on the ClientController to render the map and the chart.
My setup:
.NET 4.0, MVC3, SQL Server 2008.
Bellw goes the code of one of my methods, on the ClientController, to generate and return n ImageMap.
public ActionResult ChartMapGetClientsByType()
{
System.Web.UI.DataVisualization.Charting.Chart chart = null;
if (Session["GraficoClientePorTipo"] != null)
{
chart = (System.Web.UI.DataVisualization.Charting.Chart)Session["GraficoClientePorTipo"];
Session.Remove("GraficoClientePorTipo");
}
else
{
chart = MeuMRP.Core.Chart.CreateChartImageMap("GraficoClientePorTipo", SeriesChartType.Pie);
chart.IsMapEnabled = true;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
chart.SaveImage(ms, ChartImageFormat.Png);
Session["GraficoClientePorTipo"] = ms.ToArray();
}
return Content(chart.GetHtmlImageMap("GraficoClientePorTipo"));
}
What Am I doing wrong?
You should set the Url property to the Chart.Series object. For example:
chart.Series[0].Url = "#";
This error resulted for me on a complex chart with a set of BoxPlots.
For a simple Points chart, there was no error, the <map> was fine with coordinates and attributes.
In order for the map area coordinates to be generated, you need to add a ToolTip or a URL or MapAreaAttributes: e.g.
series.Points[idx].ToolTip = tooltip;
or
series.Points[idx].MapAreaAttributes = "onmouseover=\"DisplayTooltip('" + tooltip +"');\" onmouseout=\"DisplayTooltip('');\"";
But I found the ToolTip to be useless because it added nothing to the <area> in the <map> except for the coordinates (what am I doing wrong?). I did not test assigning a Url, assuming that works as asserted in another answer.
Adding the mouseover and mouseout MapAreaAttributes works just fine resulting in this:
<area onmouseover="DisplayTooltip('99');" onmouseout="DisplayTooltip('');" shape="rect" coords="98,44,103,49" alt="">
FYI You can find more details on setting up Web.UI Charting in MVC, at various URI, including
http://www.codeproject.com/Articles/297677/Using-ASP-Net-Charting-with-Image-Map-in-MVC
http://geekswithblogs.net/DougLampe/archive/2011/01/23/charts-in-asp.net-mvc-2-with-drill-down.aspx.

Categories

Resources