Using ASP.NET AJAX UpdatePanel with Handlers - asp.net

Im using UpdatePanel for some controls specially for captchas so, when a AsyncPostBack is performed triggered by a button "btnQuery", How can I tell to the .ashx (Handler for Captcha) to refresh it self?
Im using session to validate the Image on Captcha to the Num on the input below the image
this is the Handler :
<%# WebHandler Language="C#" Class="captcha" %>
using System;
using System.Web;
using System.Web.SessionState;
using System.Drawing;
public class captcha : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/GIF";
Bitmap imagen_GIF = new System.Drawing.Bitmap(80, 30);
Graphics grafico = System.Drawing.Graphics.FromImage(imagen_GIF);
grafico.Clear(Color.Gainsboro);
Font tipo_fuente = new Font("Comic Sans", 12, FontStyle.Bold);
string randomNum = string.Empty;
Random autoRand = new Random();
for (int x = 0; x < 5; x++)
{
randomNum += System.Convert.ToInt32(autoRand.Next(0, 9)).ToString();
}
int i_letra = System.Convert.ToInt32(autoRand.Next(65, 90));
string letra = ((char)i_letra).ToString();
randomNum += letra;
context.Session["RandomNumero"] = randomNum;
grafico.DrawString(randomNum, tipo_fuente, Brushes.Black, 5, 5);
imagen_GIF.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);
tipo_fuente.Dispose();
grafico.Dispose();
imagen_GIF.Dispose();
}
public bool IsReusable { get { return false; } }
}
I want to refresh the image.. not just doing this :
public void postbackear()
{
string script = string.Format("Sys.WebForms.PageRequestManager.getInstance()._doPostBack('{0}', '');",
btnConsulta.ID);
ScriptManager.RegisterStartupScript(this.Page, typeof(string), "Refresh", script, true);
}

Try caching options for handlers such as
context.Response.Cache.SetExpires(DateTime.Now);
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetValidUntilExpires(false);
If above not works only idea I got left is calling handler with queryString so that image source is not same any time you call
Image1.ImageUrl = "Handler.aspx?guid=" + Guid.NewGuid();

Is the image inside the UpdatePanel? I'd put it there if it isn't. Also, each time the panel updates, make sure the url for the image unique so that clients (browsers) or proxies won't use a cached image. A Guid tacked on as a querystring parameter should do the trick (e.g. YourImageHandler.ashx?xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).

Angel,
The image is not being requested again from the server, so there is no opportunity for the handler to execute. To get that to execute again, you must make the browser retrieve the image again.
That said, in your async postback, if nothing about the image is updated, the browser will have no reason to fetch it again regardless of cache settings, etc.
You could solve this with script, but an easier way is to take Myra's advice and append a GUID to the query string of the image and change that GUID as part of your async postback. This will update URL of the image needed on the client and force it to go back to the server to get the new image.
If this does not solve the problem, please post the section of your web.config that maps requests to the image handler as well as the code you use to add the image to the page.

Related

How do I write an image's MemoryStream to the page body?

I'm converting ASP.NET WebForms code to ASP.NET Core Razor pages which is new to me. I'm trying to retrieve an image MemoryStream from a business class (based on SixLabors awesome ImageSharp) and have the page render the JPEG -- no HTML, just the image. I intend to use this page elsewhere as an <img> src, like <img src="Render?imageID=42&mode=invert" />
In Render.cshtml.cs:
public class RenderModel : PageModel
{
public void OnGet()
{
//snip
Stream stream = new MemoryStream();
using (Image image1 = Image.Load(imagePath))
{
SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder encoder = new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder();
encoder.Quality = 75;
image1.Save(stream, encoder);
//image.Save("/temp/xxx.jpg", encoder); //test to see image. it works
}
Response.Clear();
//Response.Headers.ContentLength = stream.Length;
Response.ContentType = "image/jpeg";
Response.Body = stream;
}
}
...but this is not working, I get:
System.InvalidOperationException: Response Content-Length mismatch: too few bytes written (0 of 135408).
135408 is the stream.Length.
I'm probably not doing this correctly in the ASP.NET Core/Razor way. Can anyone set me straight as to how to do this? Thanks!
EDIT: commenting out the Headers.ContentLength fixes the error. But now I get a broken-image icon in the browser. Closer...
You need to write to the Response.Body isntead of replacing it.
stream.Seek(0, SeekOrigin.Begin);
await stream.CopyToAsync(Response.Body);
await Response.Body.FlushAsync();
I think Razor pages are intented to return html content.
However it seems to be possible to return different types of result in OnGet e.g. you could return a new FileContentReset (FileStreamResult seems to have issues with contentlength)
// read as bytes
public FileContentResult OnGet()
{
var image = System.IO.File.ReadAllBytes(#"c:\temp\myimage.jpeg");
return new FileContentResult(image.ToArray(), "image/jpeg");
}
// example if image comes from stream
public FileContentResult OnGet()
{
using var imageStr = System.IO.File.Open(#"c:\temp\myimage.jpeg", FileMode.Open);
using var memStr = new MemoryStream();
imageStr.CopyTo(memStr);
return new FileContentResult(memStr.ToArray(), "image/jpeg");
}
Even better maybe it to not use a Razor page and to add a MVC controller to return the result.

Importing a asp.net webPart in WebForm website from .Webpart file programmatically (Not a sharePoint Project)

We have created several user Controls (Ascx) that we render to a webpart zone. Similarly, we have a control containing WebPartManager which is implemented in all the .aspx pages.
I am working on a feature where it is required to Import generated .webpart file on any page using a file upload control.
I am Using devExpress fileUpload control and upon FileUploadComplete Event executing the below-mentioned code.
The code Runs without any error but also doesn't display any web-part in the specified zone. Which is the problem.
protected void WebPartUploadControl_FileUploadComplete(object sender, FileUploadCompleteEventArgs e)
{
string ErrorMessge = string.Empty;
if (e.UploadedFile.IsValid)
{
var xmlReader = XmlReader.Create(e.UploadedFile.FileContent);
xmlReader.Read();
System.Web.UI.WebControls.WebParts.WebPart webPart = wpManager.ImportWebPart(xmlReader, out ErrorMessge);
wpManager.AddWebPart(webPart, wpManager.Zones["Zone5"], 1);
}
}
I might be missing some fundamental code. If anybody knows the answer kindly help. Thanks .
I finally figured out the issue. Just in case if someone in future come across a similar problem, this will help.
So, The problem here is the Devexpress File-Upload control is an ajax control, making partial postback thus not updating the CatalogZone of the page which is out of its scope.
The way to deal with it is :
Create a new .WebPart file and clone the content of the uploaded file.
Re-direct to the same page which fires Page_Load event
Execute the above code in the page_Load Event in order to import.
Below is the code to explain just that :
WebPartUploadControl_FileUploadComplete
protected void WebPartUploadControl_FileUploadComplete(object sender, FileUploadCompleteEventArgs e)
{
String WebPartFilePath = Server.MapPath("DirectoryWhereYouWantTosaveCloneFile");
String WebPartFileName = "NameOfYourCloneFile.WebPart";
string FileContent = string.Empty;
Creating Directory to store data of uploaded file(.webPart).
Session["ImportWebPartFilePath"] = $"{WebPartFilePath}/{WebPartFileName}";
if (!Directory.Exists(WebPartFilePath))
{
Directory.CreateDirectory(WebPartFilePath);
}
Reading Uploaded file Data
using (StreamReader sr = new StreamReader(e.UploadedFile.FileContent))
{
FileContent = sr.ReadToEnd();
}
//Copying File Data to the newly Created file
if (!File.Exists(Session["ImportWebPartFilePath"].ToString()))
{
File.AppendAllText(WebPartFilePath + "/" + WebPartFileName, FileContent);
}
e.CallbackData = "Page Settings Imported Successfully.";
// Response.Redirect(Request.RawUrl) does not work in while ajax callback in
devexpress
// Creating a callback to current page to trigger Page_Load event.
DevExpress.Web.ASPxWebControl.RedirectOnCallback(this.Request.Path);
}
Page_Load
if (Session["ImportWebPartFilePath"] != null)
{
//Import Webpart Settings
ImportWebPartsToCurrentPage(Session["ImportWebPartFilePath"].ToString());
File.Delete(Session["ImportWebPartFilePath"].ToString());
Session["ImportWebPartFilePath"] = null;
}
ImportWebPartsToCurrentPage
private void ImportWebPartsToCurrentPage(String FilePath)
{
string ErrorMessge = string.Empty;
//Extracting All WebParts in the file
XDocument WebPartXml = XDocument.Load(FilePath);
//Spliting the each webpart.
var WebPartDescriptions = WebPartXml.Root.Elements();
try
{
foreach (var WebPartDescription in WebPartDescriptions)
{
var xmlReader = XmlReader.Create(new StringReader(WebPartDescription.ToString()));
xmlReader.Read();
// Adding Webpart to page Catalog.
System.Web.UI.WebControls.WebParts.WebPart webPart = wpManager.ImportWebPart(xmlReader, out ErrorMessge);
//Adding webpart to the page.
if (!wpManager.WebParts.Contains(webPart))
{
wpManager.AddWebPart(webPart, wpManager.Zones["ZoneName"], 0);
}
}
}
catch (Exception ex)
{
Response.Write(ex);
}
}

ExtJS: Response of too fast handler sometimes fail

I have a strange problem, that appears not always, but sometimes with the same request.
On my website (localhost) I have an ExtJS store with autoloading, and after page load (pushing F5 button) it reads JSON from some handler (*.ashx) from server. Handler gets data from DB and serializes it it JSON. It works 4 times of 5 pressing F5. 5th time json-reader shows success=false and 0 length data.
If I use time delay in handler, such as:
System.Threading.Thread.Sleep(1000);
It works 49 times of 50. But it is weird to set a latency in my response, when I try to make website faster.
Please help or ask me if there is not enough info about a problem!
Here is sample of my js:
storePrefixes.on({
'beforeload': function () {
//...
},
'load': {
fn: function() {
if (storePrefixes.data.items.length > 0)
// ... working with response
else
// here is a problem
},
single: true
}
});
And there is server code:
<%# WebHandler Language="C#" Class="GetPrefixesInRD" %>
using System;
using System.Web;
using BCR.BLL;
public class GetPrefixesInRD : IHttpHandler, System.Web.SessionState.IReadOnlySessionState
{
private readonly PrefixNewBLL prefixeBLL = new PrefixNewBLL();
private readonly Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
public void ProcessRequest(HttpContext context)
{
var prefixes = prefixeBLL.GetPrefixesByExistPrefixInAccountingDocs(null, 1, false);
prefixes.Sort((x, y) => String.CompareOrdinal(x.Prefix, y.Prefix));
context.Response.ContentType = "application/json";
context.Response.Clear();
context.Response.BufferOutput = true;
serializer.Serialize(context.Response.Output, new { root = prefixes, total = prefixes.Count });
context.Response.Flush();
context.Response.End();
}
public bool IsReusable { get { return false; } }
}
When debugging, I would check this.isLoading() to see if it is still trying to load on the odd man out. It might be better to move everything to the datachanged event. If you need to analyze the store, use console.dir(Ext.apply({}, this)); to get a snapshot at runtime.

When rendering UserControl dynamically, How do I make it use the current session?

I am rendering a custom usercontrol from a HttpHandler like such:
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string workName = context.Request.QueryString["name"];
string workForm = RenderView("~/work/" + workName + ".ascx");
context.Response.Write(workForm);
}
public static string RenderView(string path)
{
Page pageHolder = new Page();
UserControl viewControl = (UserControl)pageHolder.LoadControl(path);
pageHolder.Controls.Add(viewControl);
StringWriter result = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, result, false);
return result.ToString();
}
The problem is that the rendered page generates a new session. (I can tell by comparing the session ID for the rendered HTML with the current session ID)
How do I make the dynamic page use the current session?
Note:The code is not behind a login but will be in the future. Are there any problems I should keep in mind like supplying the session and auth cookies etc?
Make sure your HttpHandler implements marker interface IRequiresSessionState.

ASP.NET Session Problem in ASHX and using Google Chrome and Firefox

Am not sure why when using IE, retrieving session values works just fine, but when using Google Chrome and Firefox, it's not returning any?
I have already included IRequiresSessionState/IReadOnlySessionState in generic handler class, but still did not work.
So my last resort was to add my session values as a query string in generic handler.
But I still want to know why and what's wrong in Chrome and Firefox? Thanks.
UPDATE:
here's the way I handle my Seesion SessionManager
It works perfectly in ASPX pages and in IE, Chrome, and Firefox
but when used in my ASHX page. sample code below
<%# WebHandler Language="C#" Class="Upload" %>
using System;
using System.Web;
using System.Web.SessionState;
using System.IO;
public class Upload : IHttpHandler, IReadOnlySessionState
{
SessionManager sm;
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
context.Response.Expires = -1;
sm = new SessionManager();
try
{
HttpPostedFile postedFile = context.Request.Files["Filedata"];
string uploadedas = string.Empty;
if (context.Request.QueryString["as"] != null)
{
uploadedas = context.Request.QueryString["as"];
}
string username = sm.Username;
string sessionid = sm.SessionID;
//
// MORE CODES HERE
//
context.Response.Write(response);
context.Response.StatusCode = 200;
}
catch (Exception ex)
{
context.Response.Write("Error: " + ex.Message + "\r\n\r\n" + ex.StackTrace);
}
}
public bool IsReusable {
get {
return false;
}
}
}
sm.Username and sm.SessionID returns an emptry string when Chrome and Firefox is used.. but as I said earlier, those are working perfectly in ASPX pages even in different browsers.
A session is a type of cookie. Make sure you have cookies enabled on all the browsers you are testing in.
How are you calling your ashx from your page? Can you give sample code?
Do you use Flash to call the ashx? Flash has a cookie bug that always sends IE cookies to the server whichregardless of which browser you are using which makes accessing ASP.NET Session hard since it relies on a cookie.

Resources