taking screenshot of an iFrame on button click - asp.net

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.

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

how to print ASP.NET MVC2 view from server

I'm looking for a way to print ASP.NET/ Mono MVC2 view from ASP.NET application running in Windows 2003 server.
I tried code below based on Programmatically "hello world" default SERVER-side printer in ASP.NET MVC
but this outputs raw html string. How to print view as formatted text using free software?
Order layout is created as html partial view. If there is other free way to print out formatted order, I can create layout in other form instead of html.
Only free solution which I have found requires to use Windows Forms WebBrowser control but this looks not reasonable in MVC2 application which is running under Mono also.
I looked into Rotativa ( http://nuget.org/packages/Rotativa/ ) but it looks like it doesnt allow to print html.
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Web.Mvc;
public class PrintController : Controller
{
string body;
public ActionResult Complete()
{
body = RenderViewToString<TestOrder>("~/Views/Checkout/Order.ascx", new TestOrder() { Number = "1" });
PrintOrder();
return View("PaymentComplete");
}
void PrintOrder()
{
// https://stackoverflow.com/questions/12229823/programmatically-hello-world-default-server-side-printer-in-asp-net-mvc
var doc = new PrintDocument();
doc.PrinterSettings.PrinterName = "HP Laserjet 1200";
doc.PrintPage += new PrintPageEventHandler(ProvideContent);
doc.Print();
}
void ProvideContent(object sender, PrintPageEventArgs e)
{
e.Graphics.DrawString(body,
new Font("Arial", 12),
Brushes.Black,
e.MarginBounds.Left,
e.MarginBounds.Top);
}
string RenderViewToString<T>(string viewPath, T model)
{ // https://stackoverflow.com/questions/483091/render-a-view-as-a-string
ViewData.Model = model;
using (var writer = new StringWriter())
{
var view = new WebFormView(viewPath);
var vdd = new ViewDataDictionary<T>(model);
var viewCxt = new ViewContext(ControllerContext, view, vdd, new TempDataDictionary(), writer);
viewCxt.View.Render(viewCxt, writer);
return writer.ToString();
}
}
}
public class TestOrder
{
public string Number;
}
There is an article about convert HTML to PDF using iTextSharp: http://www.dotnetspider.com/resources/43589-How-convert-HTML-PDF-ASP-NET.aspx

Create image of Html code with c#

I have created html code and then save this html page as an image . The html controls which I have created is showing properly in the image with all images and background color. It is woking fine on localhost.
but I am trying to creating html code to image on the server. the image is creating but it's not showing anything like bgcolor, images, etc.
only blank image is showing.
Code :
Using Ajax calling function from client side I am sending the html content to the serverside
Server Side Method
[System.Web.Services.WebMethod()]
public static void GenerateTemplateImage(string html_Content, string TemplateName)
{
var t = new Thread(MakeScreenshot);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public static void MakeScreenshot()
{
Bitmap bitmap;
string html = string.Empty;
string Title = string.Empty;
string Meta = string.Empty;
string Style = string.Empty;
string ScriptBefore = string.Empty;
string ScriptAfter = string.Empty;
string Scripthead = string.Empty;
html="<div><div id='s_p_box-1' style='background-color: rgb(24, 0, 238); width: 109px; height: 75px;>Welcome </div>' <br/> <img id='template1' class='template' style='border:1px solid green; height:142px;width:116px' src='http://ace.demos.classicinformatics.com/Advertiser-Admin/Campaign/UserTemplate/template1.jpg'></div>";
WebBrowser wb = new WebBrowser();
wb.Navigate("about:blank");
if (wb.Document != null)
{
wb.Document.Write(html);
}
wb.DocumentText = html;
wb.ScrollBarsEnabled = false;
wb.ScriptErrorsSuppressed = true;
// Set the size of the WebBrowser control
// Take Screenshot of the web pages full width
// wb.Width = wb.Document.Body.ScrollRectangle.Width;
wb.Width = 1024;
// Take Screenshot of the web pages full height
// wb.Height = wb.Document.Body.ScrollRectangle.Height;
//wb.Height = 786;
wb.ScrollBarsEnabled = true;
if (wb.Height <= 0)
{
wb.Height = 1024;
}
//if (wb.Width <= 400)
//{
// wb.Width = 700;
//}
// Get a Bitmap representation of the webpage as it's rendered in the WebBrowser control
//Bitmap bitmap = new Bitmap(wb.Width, wb.Height);
//using (bitmap = new Bitmap(wb.Width, wb.Height))
using (bitmap = new Bitmap(wb.Width, wb.Height))
{
//wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height));
wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height));
//string imgPath = HttpContext.Current.Server.MapPath(System.Configuration.ConfigurationManager.AppSettings["ImgPath"].ToString());
//string imgPath="C:\\Projects\\aec\\Ace-A-Metric\\Advertiser-Admin\\Campaign\\UserTemplate\\";
string imgPath = URlPath + "test123" + ".bmp";
//bitmap.Save(#"D:\" + txtTempName.Text + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
bitmap.Save(imgPath, System.Drawing.Imaging.ImageFormat.Bmp);
//string imgpath = Path.Combine(HttpContext.Current.Server.MapPath("~") + "Advertiser-Admin\\Campaign\\UserTemplate\\" + txtTempName.Text +".bmp");
//bitmap.Save(imgpath, System.Drawing.Imaging.ImageFormat.Bmp);
}
wb.Dispose();
GC.Collect();
}
Do not use the WebBrowser control, it is shipped with a lot of constraints due its COM legacy, and the very poor object model.
One of the possible solution is to use Awesomium.Net
Espacially, this article explain the process : Capturing Web-Pages With C# (.NET)
The major difference, is that Awesomium and its .Net wrapper is written with no dependency to the host (actually from the Chromium source code). Then the library is actually standalone and let you consider a lots of more scenarios.

How do I create an image of a webpage and save the image to my server using .net?

I have a page that dynamically generates a small html page containing 1 small table w/text. I want to be able to take a picture (png preferable) of that page and save it to my server.
I was previously using a 3rd party solution (ABCdrawHTML2), but I have changed servers and this one does not have it. Is there a way to do it without 3rd party solutions?
This is how I do it using the Windows.Forms WebBrowser:
public class WebSiteThumbnailImage
{
string m_Url;
int m_BrowserWidth, m_BrowserHeight, m_ThumbnailWidth, m_ThumbnailHeight;
Bitmap m_Bitmap = null;
public WebSiteThumbnailImage(string url, int browserWidth, int browserHeight, int thumbnailWidth, int thumbnailHeight)
{
m_Url = url;
m_BrowserWidth = browserWidth;
m_BrowserHeight = browserHeight;
m_ThumbnailWidth = thumbnailWidth;
m_ThumbnailHeight = thumbnailHeight;
}
public Bitmap GenerateWebSiteThumbnailImage()
{
Thread m_thread = new Thread(new ThreadStart(_GenerateWebSiteThumbnailImage));
m_thread.SetApartmentState(ApartmentState.STA);
m_thread.Start();
m_thread.Join();
return m_Bitmap;
}
private void _GenerateWebSiteThumbnailImage()
{
WebBrowser m_WebBrowser = new WebBrowser();
m_WebBrowser.ScrollBarsEnabled = false;
m_WebBrowser.Navigate(m_Url);
m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
while (m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
m_WebBrowser.Dispose();
}
private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser m_WebBrowser = (WebBrowser)sender;
m_WebBrowser.ClientSize = new Size(this.m_BrowserWidth, this.m_BrowserHeight);
m_WebBrowser.ScrollBarsEnabled = false;
m_Bitmap = new Bitmap(m_WebBrowser.Bounds.Width, m_WebBrowser.Bounds.Height);
m_WebBrowser.BringToFront();
m_WebBrowser.DrawToBitmap(m_Bitmap, m_WebBrowser.Bounds);
m_Bitmap = (Bitmap)m_Bitmap.GetThumbnailImage(m_ThumbnailWidth, m_ThumbnailHeight, null, IntPtr.Zero);
}
}
To use this, at the appropriate place in your code-behind, do something like:
WebSiteThumbnailImage thumbnail = new WebSiteThumbnailImage(url, 1000, 1000, 200, 200);
Bitmap image = thumbnail.GenerateWebSiteThumbnailImage();
image.Save(filePath);

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