diff --git a/Rotativa.Demo/Rotativa.Demo.csproj b/Rotativa.Demo/Rotativa.Demo.csproj
index a4f16b7..b009393 100644
--- a/Rotativa.Demo/Rotativa.Demo.csproj
+++ b/Rotativa.Demo/Rotativa.Demo.csproj
@@ -1,5 +1,6 @@
+
Debug
AnyCPU
@@ -17,6 +18,15 @@
true
..\
true
+
+
+
+
+ 4.0
+
+
+
+
true
@@ -70,6 +80,13 @@
+
+ TestWebForms.aspx
+ ASPXCodeBehind
+
+
+ TestWebForms.aspx
+
@@ -116,6 +133,7 @@
+
Designer
@@ -172,8 +190,13 @@
+
+ 10.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
-
+
+
+
\ No newline at end of file
diff --git a/Rotativa.sln b/Rotativa.sln
index 7680568..07ab80e 100644
--- a/Rotativa.sln
+++ b/Rotativa.sln
@@ -1,10 +1,6 @@
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rotativa", "Rotativa\Rotativa.csproj", "{D93FAA11-31F0-4629-B53C-AA8680283529}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rotativa.Demo", "Rotativa.Demo\Rotativa.Demo.csproj", "{8EC08BFB-6ABA-4D71-8405-77AFF5859F3D}"
-EndProject
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{C58DBD7F-8582-4005-AD32-E94AB45A338F}"
ProjectSection(SolutionItems) = preProject
.nuget\NuGet.Config = .nuget\NuGet.Config
@@ -12,10 +8,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{C58DBD
.nuget\NuGet.targets = .nuget\NuGet.targets
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rotativa", "Rotativa\Rotativa.csproj", "{D93FAA11-31F0-4629-B53C-AA8680283529}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rotativa.Demo", "Rotativa.Demo\Rotativa.Demo.csproj", "{8EC08BFB-6ABA-4D71-8405-77AFF5859F3D}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rotativa.Tests", "Rotativa.Tests\Rotativa.Tests.csproj", "{DE9EB72A-2AE7-42E8-9A44-AA525B463688}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rotativa.UnitTests", "Rotativa.UnitTests\Rotativa.UnitTests.csproj", "{26A2783C-662D-4885-BD2B-A9AFB55C6BF9}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rotativa.MVC4", "Rotativa.MVC4\Rotativa.MVC4.csproj", "{733E5EA3-068F-439D-B0F9-35D06C668657}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -38,6 +40,10 @@ Global
{26A2783C-662D-4885-BD2B-A9AFB55C6BF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26A2783C-662D-4885-BD2B-A9AFB55C6BF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26A2783C-662D-4885-BD2B-A9AFB55C6BF9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {733E5EA3-068F-439D-B0F9-35D06C668657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {733E5EA3-068F-439D-B0F9-35D06C668657}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {733E5EA3-068F-439D-B0F9-35D06C668657}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {733E5EA3-068F-439D-B0F9-35D06C668657}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Rotativa/AsPdfResultBase.cs b/Rotativa/AsPdfResultBase.cs
index 744253e..db24bf3 100644
--- a/Rotativa/AsPdfResultBase.cs
+++ b/Rotativa/AsPdfResultBase.cs
@@ -15,6 +15,9 @@ namespace Rotativa
{
public abstract class AsPdfResultBase : ActionResult
{
+ protected Regex _urlRootReplacement = new Regex(@"( href=[""']| src=[""']|[ :]url\()/", RegexOptions.IgnoreCase | RegexOptions.Multiline);
+ protected Regex _urlRelativeReplacement = new Regex(@"( href=[""']| src=[""']|[ :]url\()(?!(?:http|https|ftp):)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
+
private const string ContentType = "application/pdf";
///
diff --git a/Rotativa/HtmlAsPdf.cs b/Rotativa/HtmlAsPdf.cs
new file mode 100644
index 0000000..2c7ee28
--- /dev/null
+++ b/Rotativa/HtmlAsPdf.cs
@@ -0,0 +1,92 @@
+using System;
+using System.IO;
+using System.Web;
+using System.Web.Mvc;
+
+namespace Rotativa
+{
+ ///
+ /// Allow a developer to render HTML as a PDF
+ ///
+ public class HtmlAsPdf : AsPdfResultBase
+ {
+ ///
+ /// Constructor
+ ///
+ public HtmlAsPdf()
+ {
+ WkhtmltopdfPath = String.Empty;
+ }
+
+ ///
+ /// Returns an empty string, as Wkhtmltopdf will receive our HTML directly.
+ ///
+ /// An empty string.
+ protected override string GetUrl(ControllerContext context)
+ {
+ return String.Empty;
+ }
+
+ ///
+ /// Render a PDF representation of the passed markup.
+ ///
+ /// The markup to render as PDF.
+ /// A binary byte-array containing the rendered PDF.
+ protected byte[] CallTheDriver(String html)
+ {
+ // replace href and src attributes with full URLs
+ string baseUrl = string.Format("{0}://{1}/", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority);
+ string relativeUrl = string.Format("{0}://{1}{2}", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority, HttpContext.Current.Request.Url.AbsolutePath);
+
+ if (!relativeUrl.EndsWith("/")) relativeUrl = relativeUrl + "/";
+
+ string buffer = _urlRootReplacement.Replace(html, String.Format("$1{0}", baseUrl));
+ buffer = _urlRelativeReplacement.Replace(buffer, String.Format("$1{0}", relativeUrl));
+
+ var fileContent = WkhtmltopdfDriver.ConvertHtml(WkhtmltopdfPath, GetConvertOptions(), buffer);
+ return fileContent;
+ }
+
+ [Obsolete("Not Used By HtmlAsPdf", true)]
+ protected override byte[] CallTheDriver(ControllerContext context) { throw new NotImplementedException("This class only used to render WebForms"); }
+
+ ///
+ /// Render a PDF representation of the passed markup.
+ /// Will handle default filepaths, and saving copies to server.
+ ///
+ /// The markup to render as PDF.
+ /// A binary byte-array containing the rendered PDF.
+ public byte[] BuildPdf(String html)
+ {
+ if (html == null)
+ throw new ArgumentNullException("html");
+
+ if (WkhtmltopdfPath == string.Empty)
+ WkhtmltopdfPath = HttpContext.Current.Server.MapPath("~/Rotativa");
+
+ var fileContent = CallTheDriver(html);
+
+ if (string.IsNullOrEmpty(SaveOnServerPath) == false)
+ {
+ File.WriteAllBytes(SaveOnServerPath, fileContent);
+ }
+
+ return fileContent;
+ }
+
+ ///
+ /// Render a PDF representation of the passed markup.
+ ///
+ /// The markup to render as PDF.
+ public void ExecuteResult(String html)
+ {
+ var context = new HttpContextWrapper(HttpContext.Current);
+
+ var fileContent = this.BuildPdf(html);
+
+ var response = this.PrepareResponse(context.Response);
+
+ response.OutputStream.Write(fileContent, 0, fileContent.Length);
+ }
+ }
+}
diff --git a/Rotativa/PageAsPdf.cs b/Rotativa/PageAsPdf.cs
new file mode 100644
index 0000000..c34c2d7
--- /dev/null
+++ b/Rotativa/PageAsPdf.cs
@@ -0,0 +1,33 @@
+using System;
+using System.IO;
+using System.Web;
+using System.Web.UI;
+
+namespace Rotativa
+{
+ public class PageAsPdf : System.Web.UI.Page
+ {
+ protected HtmlAsPdf PDF = new HtmlAsPdf();
+
+ protected override void Render(System.Web.UI.HtmlTextWriter writer)
+ {
+ // Check that we're not already rendering a PDF
+ if (HttpContext.Current.Items["Rotativa.RenderingPDF"] as Boolean? != true)
+ {
+ // Flag the context so that we don't go into stack overflow
+ HttpContext.Current.Items["Rotativa.RenderingPDF"] = true;
+
+ StringWriter sw = new StringWriter();
+ HtmlTextWriter hw = new HtmlTextWriter(sw);
+ // Render the page to our StringWriter
+ base.Render(hw);
+
+ // Render the PDF
+ this.PDF.ExecuteResult(sw.ToString());
+ }
+ else
+ // Render the page normally
+ base.Render(writer);
+ }
+ }
+}
diff --git a/Rotativa/Rotativa.csproj b/Rotativa/Rotativa.csproj
index e5145ea..7767284 100644
--- a/Rotativa/Rotativa.csproj
+++ b/Rotativa/Rotativa.csproj
@@ -45,6 +45,10 @@
+
+ ASPXCodeBehind
+
+
diff --git a/Rotativa/ViewAsPdf.cs b/Rotativa/ViewAsPdf.cs
index e191bcf..08dfeea 100644
--- a/Rotativa/ViewAsPdf.cs
+++ b/Rotativa/ViewAsPdf.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Text;
+using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
@@ -101,11 +102,15 @@ protected override byte[] CallTheDriver(ControllerContext context)
StringBuilder html = sw.GetStringBuilder();
// replace href and src attributes with full URLs
- string baseUrl = string.Format("{0}://{1}", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority);
- html.Replace(" href=\"/", string.Format(" href=\"{0}/", baseUrl));
- html.Replace(" src=\"/", string.Format(" src=\"{0}/", baseUrl));
+ string baseUrl = string.Format("{0}://{1}/", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority);
+ string relativeUrl = string.Format("{0}://{1}{2}", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority, HttpContext.Current.Request.Url.AbsolutePath);
- var fileContent = WkhtmltopdfDriver.ConvertHtml(WkhtmltopdfPath, GetConvertOptions(), html.ToString());
+ if (!relativeUrl.EndsWith("/")) relativeUrl = relativeUrl + "/";
+
+ string buffer = _urlRootReplacement.Replace(html.ToString(), String.Format("$1{0}", baseUrl));
+ buffer = _urlRelativeReplacement.Replace(buffer, String.Format("$1{0}", relativeUrl));
+
+ var fileContent = WkhtmltopdfDriver.ConvertHtml(WkhtmltopdfPath, GetConvertOptions(), buffer);
return fileContent;
}
}
diff --git a/Rotativa/WkhtmltopdfDriver.cs b/Rotativa/WkhtmltopdfDriver.cs
index e307f59..c427a13 100644
--- a/Rotativa/WkhtmltopdfDriver.cs
+++ b/Rotativa/WkhtmltopdfDriver.cs
@@ -53,19 +53,19 @@ private static byte[] Convert(string wkhtmltopdfPath, string switches, string ht
}
var proc = new Process
- {
- StartInfo = new ProcessStartInfo
- {
- FileName = Path.Combine(wkhtmltopdfPath, "wkhtmltopdf.exe"),
- Arguments = switches,
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- RedirectStandardInput = true,
- WorkingDirectory = wkhtmltopdfPath,
- CreateNoWindow = true
- }
- };
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = Path.Combine(wkhtmltopdfPath, "wkhtmltopdf.exe"),
+ Arguments = switches,
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ RedirectStandardInput = true,
+ WorkingDirectory = wkhtmltopdfPath,
+ CreateNoWindow = true
+ }
+ };
proc.Start();
// generate PDF from given HTML string, not from URL