Has Anyone Got HTTP Compression Working with ASP.NET? - asp.net

I've spent quite a bit of time on this but seem to be going nowhere. I have a large page that I really want to speed up. The obvious place to start seems to be HTTP compression, but I just can't seem to get it to work for me.
After considerable searching, I've tried several variations of the code below. It kind of works, but after refreshing the browser, the results seem to fall apart. They were turning to garbage when the page used caching. If I turn off caching, then the page seems right but I lose my CSS formatting (stored in a separate file) and get an error that an included JS file contains invalid characters.
Most of the resources I've found on the Web were either very old or focused on accessing IIS directly. My page is running on a shared hosting account and I do not have direct access to IIS7, which it's running on.
protected void Application_BeginRequest(object sender, EventArgs e)
{
// Implement HTTP compression
if (Request["HTTP_X_MICROSOFTAJAX"] == null) // Avoid compressing AJAX calls
{
// Retrieve accepted encodings
string encodings = Request.Headers.Get("Accept-Encoding");
if (encodings != null)
{
// Verify support for or gzip (deflate takes preference)
encodings = encodings.ToLower();
if (encodings.Contains("gzip") || encodings == "*")
{
Response.Filter = new GZipStream(Response.Filter,
CompressionMode.Compress);
Response.AppendHeader("Content-Encoding", "gzip");
Response.Cache.VaryByHeaders["Accept-encoding"] = true;
}
else if (encodings.Contains("deflate"))
{
Response.Filter = new DeflateStream(Response.Filter,
CompressionMode.Compress);
Response.AppendHeader("Content-Encoding", "deflate");
Response.Cache.VaryByHeaders["Accept-encoding"] = true;
}
}
}
}
Is anyone having better success with this?

I've had good results using GZipStream and DeflateStream to write the output directly, although I'm not familiar with the Response.Filter property. Give this a whirl:
string response = "your output body";
string accept = Request.Headers["Accept-Encoding"];
if(accept == null) accept = "";
if (response.Length < 100 || !(accept.Contains("deflate") || accept.Contains("gzip")))
Response.Write(response);
else
{
byte[] compressed;
bool useDeflate = accept.Contains("deflate");
using (MemoryStream stream = new MemoryStream())
{
using (Stream deflate = useDeflate
? (Stream)new DeflateStream(stream, CompressionMode.Compress, true)
: (Stream)new GZipStream(stream, CompressionMode.Compress, true))
using (StreamWriter writer = new StreamWriter(deflate))
writer.Write(response);
compressed = new byte[stream.Length];
stream.Position = 0;
stream.Read(compressed, 0, compressed.Length);
}
Response.Headers["Content-Encoding"] = useDeflate ? "deflate" : "gzip";
Response.BinaryWrite(compressed);
}

Related

Crystal report method not found

I made a feedback project. I made it on ASP.NET MVC 5 it also has crystal reports. reports were working fine, but suddenly they stopped to work. I don't what happened with them. but since last week I tried hard to find solution but unfortunately could not get the right one who solved the solution. I downloaded different run times but all went vain. this is the bottom line of error.
"Method not found: 'CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag CrystalDecisions.ReportAppServer.ReportDefModel.ISCRExportOptions.get_ExportOptionsEx()'"
this is the code:
public CrystalReportFeedback UserFeedbackDateWise(FeedbackReport be){
if (Session["CurrentUser"] != null && Convert.ToInt32(Session["User_Id"]) != 0)
{
string reportPath = Path.Combine(Server.MapPath("~/Reports"), "UserFeedbackReport.rpt");
if (ModelState.IsValid)
{
be.FromDate = Convert.ToDateTime(TempData["UserFromDate"]);
be.ToDate = Convert.ToDateTime(TempData["UserToDate"]);
be.User_Id = Convert.ToInt32(Session["User_Id"]);
}
return new CrystalReportFeedback(reportPath, be);
}
else
{
return null;
//new CrystalReportFeedback(reportPath, be);
}
}
Init of the report :
public CrystalReportFeedback(string reportPath, FeedbackReport be)//, object dataSet)
{
//int[] array;
string strConnect = Convert.ToString(System.Configuration.ConfigurationManager.ConnectionStrings["TSC"]);
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(strConnect);
string _username = builder.UserID;
string _pass = builder.Password;
string _server = builder.DataSource;
string _database = builder.InitialCatalog;
ReportDocument reportDocument = new ReportDocument();
//
reportDocument.Load(reportPath);
reportDocument.SetDatabaseLogon(_username, _pass, _server, _database);
if (be.Region_Id != 0)
{
reportDocument.SetParameterValue("#Region_Id", be.Region_Id);
}
if (be.User_Id != 0)
{
reportDocument.SetParameterValue("#User_Id", be.User_Id);
}
reportDocument.SetParameterValue("#FromDate", be.FromDate);
reportDocument.SetParameterValue("#ToDate", be.ToDate);
//reportDocument.ExportToDisk(ExportFormatType.PortableDocFormat, "C:\report.pdf");
_contentBytes = StreamToBytes(reportDocument.ExportToStream(ExportFormatType.PortableDocFormat));
}
Export method :
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.ApplicationInstance.Response;
response.Clear();
response.Buffer = false;
response.ClearContent();
response.ClearHeaders();
response.Cache.SetCacheability(HttpCacheability.Public);
response.ContentType = "application/pdf";
using (var stream = new MemoryStream(_contentBytes))
{
stream.WriteTo(response.OutputStream);
stream.Flush();
}
}
private static byte[] StreamToBytes(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Hope that I will get my solution at earliest.
this is modified code:
[HttpGet]
public FileResult UserFeedbackDateWise(FeedbackReport be)
{
if (Session["CurrentUser"] != null && Convert.ToInt32(Session["User_Id"]) != 0)
{
string reportPath = Path.Combine(Server.MapPath("~/Reports"), "UserFeedbackReport.rpt");
if (ModelState.IsValid)
{
be.FromDate = Convert.ToDateTime(TempData["UserFromDate"]);
be.ToDate = Convert.ToDateTime(TempData["UserToDate"]);
be.User_Id = Convert.ToInt32(Session["User_Id"]);
}
string strConnect = Convert.ToString(System.Configuration.ConfigurationManager.ConnectionStrings["TSC"]);
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(strConnect);
string _username = builder.UserID;
string _pass = builder.Password;
string _server = builder.DataSource;
string _database = builder.InitialCatalog;
ReportDocument reportDocument = new ReportDocument();
//
reportDocument.Load(reportPath);
reportDocument.SetDatabaseLogon(_username, _pass, _server, _database);
if (be.Region_Id != 0)
{
reportDocument.SetParameterValue("#Region_Id", be.Region_Id);
}
if (be.User_Id != 0)
{
reportDocument.SetParameterValue("#User_Id", be.User_Id);
}
reportDocument.SetParameterValue("#FromDate", be.FromDate);
reportDocument.SetParameterValue("#ToDate", be.ToDate);
Stream stream = reportDocument.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat);
//Here i have my stream with my pdf report, i just create a new FileStreamResult and return it to my client like that :
FileStreamResult myfile = new FileStreamResult(stream, "application/pdf");
return myfile;
//new CrystalReportFeedback(reportPath, be);
}
else
{
return null;
//new CrystalReportFeedback(reportPath, be);
}
}
This isn't a coding issue, it's a runtime issue. The version of the crystal runtime or the bitness of your application.
One thing to try first is to upgrade both your development version and ensure you're running the same version in production. See https://apps.support.sap.com/sap/support/knowledge/public/en/2148492 for more details
It says:
Compile your application either to 'X86 mode' or 'X64 mode'
Install the particular versions of runtimes on deployment machine.
i.e. If the application is compiled as 32 bit, then install the 32bit runtimes.
I'll try my best to help you exporting your report, but your post is not very clear. For your next post try to be very specific and provide as much information as you can.
I currently made a MVC project and export a crystalreport report from my controller to my client.
I think that your ExecuteResult method can work, but working with the httpcontext is useless, Crystalreport and .NET provide some useful methods to do the same.
So i'll show you how i create and export my report so you can copy / paste and modify your code.
Here is my controller method, called from a button :
[HttpGet]
public FileResult InitReport()
{
//I create my report here
FileImportReport rptH = new FileImportReport();
// Some configuration on the report, datasource, databaselogon .. etc
...
//
//Then I export my report to a pdf stream like that :
Stream stream = rptH.ExportToStream(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat);
//Here i have my stream with my pdf report, i just create a new FileStreamResult and return it to my client like that :
FileStreamResult myfile = new FileStreamResult(stream, "application/pdf");
return myfile;
}
My method is called from a button but it can work like you want, or the file can be saved in any known path.
You can test to reproduce my code, in your CrystalReportFeedback method use my code with your reportDocument object, you don't need to use your StreamToBytes method.
Regards,
EDIT : Useful links with your error :
Crystal Reports exception in Visual Studio 2013
https://www.arcanadev.com/support/kb/K00000499.aspx

Download File Servlet - File Content contains binary

I had tried to develop a servlet that allow user to download file but it allow user to download the file but the file content contains binary garbage and not human readable. May I know what could be the reason ?
Code
int length = -1, index = 0;
byte[] buffer = null;
String attachmentPath = null, contentType = null, extension = null;
File attachmentFile = null;
BufferedInputStream input = null;
ServletOutputStream output = null;
ServletContext context = null;
attachmentPath = request.getParameter("attachmentPath");
if (attachmentPath != null && !attachmentPath.isEmpty()) {
attachmentFile = new File(attachmentPath);
if (attachmentFile.exists()) {
response.reset();
context = super.getContext();
contentType = context.getMimeType(attachmentFile.getName());
response.setContentType(contentType);
response.addHeader("content-length", String.valueOf(attachmentFile.length()));
response.addHeader("content-disposition", "attachment;filename=" + attachmentFile.getName());
try {
buffer = new byte[AttachmentTask.DEFAULT_BUFFER_SIZE];
input = new BufferedInputStream(new FileInputStream(attachmentFile));
output = response.getOutputStream();
while ((length = input.read(buffer)) != -1) {
output.write(buffer, 0, length);
index += length;
// output.write(length);
}
output.flush();
input.close();
output.close();
} catch (FileNotFoundException exp) {
logger.error(exp.getMessage());
} catch (IOException exp) {
logger.error(exp.getMessage());
}
} else {
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} catch (IOException exp) {
logger.error(exp.getMessage());
}
}
It is relate to writing file as binary or text mode or browser settings?
Please help.
Thanks.
The problem is not in the code given so far. You're properly using InputStream/OutputStream instead of a Reader/Writer to stream the file.
The cause of the problem is more likely in the way how you created/saved the file. This problem will manifest when you've used a Reader and/or Writer which is not been instructed to use the proper character encoding for the characters being read/written. Perhaps you're creating an upload/download service and the fault was in the upload process itself?
Assuming that the data is in UTF-8, you should have created the reader as follows:
Reader reader = new InputStreamReader(new FileInputStream(file), "UTF-8"));
and the writer as follows:
Writer writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
But if you actually don't need to manipulate the stream on a per-character basis, but just wanted to transfer the data unmodified, then you should actually have used InputStream/OutputStream all the time.
See also:
Unicode - How to get the characters right?

Content service returns old content for some time

I'm using following snippet for saving content:
private void writeToFile(NodeRef nodeRef, String content) throws IOException {
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
InputStream contentStream = new ByteArrayInputStream(content.getBytes(encoding));
writer.setMimetype(mimeType);
writer.setEncoding(encoding);
writer.putContent(contentStream);
Map<QName, Serializable> repoProps = nodeService.getProperties(nodeRef);
ContentData contentData = (ContentData) repoProps.get(ContentModel.PROP_CONTENT);
if(contentData == null)
contentData = writer.getContentData();
contentData = ContentData.setEncoding(contentData, encoding);
contentData = ContentData.setMimetype(contentData, mimeType);
repoProps.put(ContentModel.PROP_CONTENT, contentData);
contentStream.close();
nodeService.setProperties(nodeRef, repoProps);
}
When I read content written this way within short period of time (depends on server load) in other place, old content is returned. So it looks like that maybe indexing is in progress, so before final commit old content is returned, is that possible? If so, is it possible to override this behavior and access newest possible content? Via contentUrl?
To avoid this behavior I'm using thread for each read request, which sleeps for some time at the beginning, but I really dislike this "solution".
Edit: I built from newest SVN source, running on Tomcat 6.0.35 on Linux (CentOS and Ubuntu); system load - i mean hundreds of files changing every few seconds.
Edit: reading looks like this:
private byte[] readFileContent(NodeRef nodeRef) throws IOException {
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
if(reader == null)
return null;
InputStream originalInputStream = reader.getContentInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final int BUF_SIZE = 1 << 8; // 1KiB buffer
byte[] buffer = new byte[BUF_SIZE];
int bytesRead = -1;
while ((bytesRead = originalInputStream.read(buffer)) > -1) {
outputStream.write(buffer, 0, bytesRead);
}
originalInputStream.close();
return outputStream.toByteArray();
}
Ok, solved with simplier saving like this:
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
InputStream contentStream = new ByteArrayInputStream(content.getBytes(encoding));
writer.setMimetype(mimeType);
writer.setEncoding(encoding);
writer.putContent(contentStream);
contentStream.close();
Previous saving was at place because of some content encoding problems, so testing shows if this works.

taking screenshot of an iFrame on button click

Hello i am creating a website having an iFrame and a button.The function of that button is to get the screenshot of whatever that is displayed inside the iFrame and save it as an image on the harddisk.Below is the code i am using
private void saveURLToImage(string url)
{
if (!string.IsNullOrEmpty(url))
{
string content = "";
System.Net.WebRequest webRequest = WebRequest.Create(url);
System.Net.WebResponse webResponse = webRequest.GetResponse();
System.IO.StreamReader sr = new StreamReader(webResponse.GetResponseStream(), System.Text.Encoding.GetEncoding("UTF-8"));
content = sr.ReadToEnd();
//save to file
byte[] b = Convert.FromBase64String(content);
System.IO.MemoryStream ms = new System.IO.MemoryStream(b);
System.Drawing.Image img = System.Drawing.Image.FromStream(ms);
img.Save(#"c:\pic.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
img.Dispose();
ms.Close();
}
}
And here is the code for button click
protected void Button1_Click(object sender, ImageClickEventArgs e)
{
saveURLToImage("http://www.google.com");
}
However when i click on the button i am getting an error
The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or a non-white space character among the padding characters.
on this line
byte[] b = Convert.FromBase64String(content);
i am unable to figure out how to resolve it.Any help would be greatly appreciated.Thank you
In your case content is the raw HTML that makes the page up, not how it is rendered - that would be up to the browser to decide (have a look at it in the debugger) so, since that is not base 64 (which is a way to encode binary data using just ASCII characters), in order for this to work you would need to get the base 64 encoded binary data of a JPEG encoded image of however the browser has rendered the HTML, which you do not have.
I think this is not an easy thing to achieve in a web application since in the .net code you are running on the server and it is the job of the client to render the HTML into something that you can take a screenshot of. You could (and this will probably be really fragile so I would not really recommend it, hosting a winforms control like this in a web application is usually a recipe for trouble, but I think it may be possible) use a browser control on your server side and set the URL of that but then you would need to somehow screenshot it - this might help: Taking Website Screenshots With The WebBrowser Control.
Update
Tucked away in the comments of the web site I linked last is some code that actually works to take a screenshot of a web page (using a WebBrowser control). It requires that you have references to the following:
System.Drawing
System.Windows.Forms
Microsoft HTML Object Library (this is a COM reference, not a .NET one)
Here is a class that does the job we want (has just a single Render method on it that takes a Uri and a Size and returns a Bitmap):
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using mshtml;
public class HtmlToBitmapConverter
{
public Bitmap Render(Uri uri, Size size)
{
var browser = new WebBrowser
{
ScrollBarsEnabled = false,
ScriptErrorsSuppressed = true,
Size = size
};
browser.BringToFront();
NavigateAndWaitForLoad(browser, uri, 0);
var bitmap = new Bitmap(size.Width, size.Height);
GetImage(browser.Document.DomDocument, bitmap, Color.White);
return bitmap;
}
private void NavigateAndWaitForLoad(WebBrowser browser,
Uri uri,
int waitTime)
{
const int sleepTimeMiliseconds = 5000;
browser.Navigate(uri);
var count = 0;
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Thread.Sleep(sleepTimeMiliseconds);
Application.DoEvents();
count++;
if (count > waitTime / sleepTimeMiliseconds)
{
break;
}
}
while (browser.Document.Body == null)
{
Application.DoEvents();
}
var document = (IHTMLDocument2)browser.Document.DomDocument;
var style = (IHTMLStyle2)document.body.style;
style.overflowX = "hidden";
style.overflowY = "hidden";
}
private static void GetImage(object obj,
Image destination,
Color backgroundColor)
{
using (var graphics = Graphics.FromImage(destination))
{
var deviceContextHandle = IntPtr.Zero;
var rectangle = new Rect
{
Right = destination.Width,
Bottom = destination.Height
};
graphics.Clear(backgroundColor);
try
{
deviceContextHandle = graphics.GetHdc();
var viewObject = (IViewObject)obj;
viewObject.Draw(1,
-1,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
deviceContextHandle,
ref rectangle,
IntPtr.Zero,
IntPtr.Zero,
0);
}
finally
{
if (deviceContextHandle != IntPtr.Zero)
{
graphics.ReleaseHdc(deviceContextHandle);
}
}
}
}
[ComImport]
[Guid("0000010D-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IViewObject
{
void Draw([MarshalAs(UnmanagedType.U4)] uint dwAspect,
int lindex,
IntPtr pvAspect,
[In] IntPtr ptd,
IntPtr hdcTargetDev,
IntPtr hdcDraw,
[MarshalAs(UnmanagedType.Struct)] ref Rect lprcBounds,
[In] IntPtr lprcWBounds,
IntPtr pfnContinue,
[MarshalAs(UnmanagedType.U4)] uint dwContinue);
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
}
NOTE As I said before, I am not sure this is a great idea to be used in a web application for a couple of reasons:
It is a Windows Forms control so the way it deals with memory may not be compatible with being used in a web application.
It means that the account taking the screenshot will be the one that the web application is running as, not necessarily the end user.
OK, so I think the above would be fine in a winforms app but maybe not appropriate for the web, but, hey, we can make it work anyway, here goes...
I am assuming you are going for a regular ASP .NET web application in which case you would have something like this in the .aspx page:
<asp:Button runat="server" OnClick="TakeScreenShot" Text="Take Screenshot"/>
Then in the code behind the TakeScreenshot method would look like this:
protected void TakeScreenShot(object sender, EventArgs e)
{
Uri uri = new Uri("http://www.google.com");
// Because it is a WebBrowser control it needs to run in an STA
// thread - what we will do is render the image to a Bitmap then
// store the raw bytes in this byte array from a newly created
// thread
byte[] screenshot = null;
var t = new Thread(() =>
{
using (var ms = new MemoryStream())
{
// The screenshot object contains a 640x480
// screenshot
var bitmap = new HtmlToBitmapConverter()
.Render(uri,
new Size(640, 480));
bitmap.Save(ms, ImageFormat.Jpeg);
screenshot = ms.ToArray();
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
// Here we have the JPEG encoded bytes of the image - we can
// just save them to a file like so...
using (var f = File.Create(#"c:\google.jpg"))
{
f.Write(screenshot, 0, screenshot.Length);
}
}
There you go - c:\google.jpg will have a screenshot of Google in it.

Caching Files in the Browser

By using the below function I am caching js, css file in the browser.
Like wise I want to cahe the Image in the browser.
private static void CacheOrFetchFromServer(string relativePath, string absolutePath, HttpContext context)
{
Cache cache = HttpRuntime.Cache;
string content;
if (cache[relativePath] == null)
{
Encoding encoding = Encoding.GetEncoding(DefaultEncodingCodePage);
CacheDependency dependency = new CacheDependency(absolutePath);
content = File.ReadAllText(absolutePath, encoding);
cache.Insert(relativePath, content, dependency);
}
else
{
content = cache[relativePath].ToString();
}
using (StreamWriter sw = new StreamWriter(context.Response.OutputStream))
{
sw.Write(content);
}
}
I had tried the below one to cache the image. But it didn't show the image.
private static void CacheOrFetchImageFileFromServer(string relativePath, string absolutePath, HttpContext context)
{
string extension = System.IO.Path.GetExtension(relativePath);
if (extension.ToUpper() == ".JPG" || extension.ToUpper() == ".PNG" || extension.ToUpper() == ".GIF" || extension.ToUpper() == ".TIFF")
{
Cache cache = HttpRuntime.Cache;
System.Drawing.Image imgPhoto = null;
if (cache[relativePath] == null)
{
Encoding encoding = Encoding.GetEncoding(DefaultEncodingCodePage);
CacheDependency dependency = new CacheDependency(absolutePath);
FileStream fs = File.OpenRead(absolutePath);
byte[] data = new byte[fs.Length];
fs.Read(data, 0, data.Length);
MemoryStream ms = new MemoryStream(data);
Bitmap bmp = new Bitmap(ms);
imgPhoto = System.Drawing.Image.FromFile(absolutePath);
cache.Insert(relativePath, bmp, dependency);
}
else
{
imgPhoto = (Image) cache[relativePath];
}
context.Response.Write(absolutePath);
//using (StreamWriter sw = new StreamWriter(context.Response.OutputStream))
//{
// sw.Write(absolutePath);
//}
}
}
I'm not sure I understand what you're doing here.
First of all, the Cache object in asp.net is used to cache data on the server side, not on the client side (browser).
Caching of files, specially css, JavaScript and images, is done by the browser automatically, you don't have to do this manually for every file. And even if you had to do this manually, this isn't the way - it looks like you're just creating a copy of the file on the server's cache (I havn't done tests, but I trust Microsoft and assume this is already done in some way, and your way is actually slower).
If you want greater control over client side caching, you can enable content expiration on the IIS.

Resources