How to Render XML from IE in a HTTPS Page? - asp.net

I have some advanced users who need to see the raw XML of a transaction. I thought I could just have a link on the source page (with target="_blank") to a new page that would just output the XML using Response.Write, having set the Content-Disposition header to inline, and Response.ContentType to "text/xml".
That works nicely with FireFox and Chrome, but in IE10, I get the security warning about "Do you want to view only the webpage content that was delivered securely?"
Research shows that this message is displayed when the page contains "mixed content". That is, when some of the content is in "https", and some is in "http". That is not the case in my scenario, as the entire content is just the XML document, which doesn't even contain a reference to "http" in it.
I found several articles about this, and they suggest changing the page to use only https, or changing the IE security settings to "Enable" mixed content without prompting:
http://blog.httpwatch.com/2009/04/23/fixing-the-ie-8-warning-do-you-want-to-view-only-the-webpage-content-that-was-delivered-securely/
http://blogs.msdn.com/b/ieinternals/archive/2009/06/22/https-mixed-content-in-ie8.aspx
http://blog.httpwatch.com/2009/09/17/even-more-problems-with-the-ie-8-mixed-content-warning/
But, again, I have no "http" content on the "page"!
How can I display "raw" XML content in IE without this prompt?

I did this for an internal debugging app i made. It works in IE without any issues/popups. BUT, it's not really "raw XML", but more like xml -> html displayed in a div (still looks like XML though) as plain text. I made it using webapi, and also used angularjs, but you can change the angular to straight jquery.
Not sure if you're only after a straight up raw XML answer, but if you just want to display XML in text form, this should help you or at least give you some inspiration lol:
api action: returns xml through ajax. The webresponse().response = string that contains xml.
public HttpResponseMessage GetResponse(RequestDTO requestDTO)
{
return new HttpResponseMessage()
{
Content = WebResponse(requestDTO).Response
};
}
angular part:
$http.post('api/getresponse', requestData)
.success(function (data) {
$scope.response.xml = data;
});
html part:
<h3>XML Response</h3>
<pre highlight="response.xml" class="xml response"></pre>
Edit
To answer your questions:
"highlight" is a directive, and i think i originally made it because i was going to try and add code highlighting, but never did. But all it does is this:
angular.element(elem).text(value);
equivalent to the $(jquery).text(value); function.
As for the xml/response class, all it does is XDocument.Parse(xml), and return as new StringContent();
edited snippet from my code:
protected ResponseDTO WebResponse(RequestDTO requestDTO)
{
//....
var response = myRequest.GetXmlResponse(webResponse);
return new ResponseDTO()
{
Headers = new StringContent("....");
Response = new StringContent(response.ToString())
};
}
public XDocument GetXmlResponse(HttpWebResponse webResponse)
{
return XDocument.Parse(xmlResponse(webResponse, Encoding.UTF8));
}
the ajax is returned as Content-Type: text/plain; charset=utf-8

Related

How to render area of ASP .Net Core razor page (for pdf)

I am writing an ASP.Net Core Web App with Razor pages and need to render part of a page to a PDF. I'm pretty sure the actual PDF creation should be simple using one of the pdf libraries available like jsreport. I found several samples for rendering a page to a string which is great except I only want the report area.
What I'm struggling with is how to render just a portion of my page for the PDF. This image shows basically how my page is structured. The header, nav and footer come from the _Layout for my app. The range partial is shared by all the report pages and the report content is the actual page.
Is there a way to render just a section of a page?
If the content area was also a partial could that be rendered separately?
I have almost no experience with UI development so please pardon my naivety :)
Here is my solution to render the report area of my page.
The simple answer is, post the html content of the page section I want to render back to the server, render it to a PDF and return that as a file for downloading.
To do this I first needed to get the html content for the section of the page containing the report. I did this by setting the id of the div for my reports to “report-content” and then using some script to capture that html.
$(function () {
$("#btnSubmit").click(function () {
$("input[name='ReportContent']").val($("#report-content").html());
});
});
The form to submit the request has a hidden “ReportContent” element where the html is stored.
#using (Html.BeginForm("Export", "Home", FormMethod.Post))
{
<input type="hidden" name="ReportContent" />
<input type="submit" id="btnSubmit" value="Download PDF" />
}
On the server side I created a method using JsReport API to render the PDF from the html.
protected async Task<IActionResult> RenderPDFAsync(string content)
{
var rs = new LocalReporting().UseBinary(JsReportBinary.GetBinary()).AsUtility().Create();
var report = await rs.RenderAsync(new RenderRequest()
{
Template = new Template()
{
Recipe = Recipe.ChromePdf,
Engine = Engine.None,
Content = content
}
});
return new FileStreamResult(report.Content, new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/pdf"));
}
Finally, I added the handler for the post that renders the PDF and returns the file result to each report page.
public async Task<IActionResult> OnPostAsync()
{
return await RenderPDFAsync(Request.Form["ReportContent"].ToString());
}
My code has a bit more validation than shown here and I have a common PageModel derived base class for all of my report pages so the only thing required for new reports is adding the post hander and setting the id on the section to be included in the PDF. I also intend to move the rendering to a service so it can be shared rather than recreated every time a report is created.

Iframe shows ActionMethod name while loading PDF file in ASP MVC

i am using iframe tag in order to call ActionMethod that returns FileResult to display PDF file. The issue is after it loads PDF document instead of showing pdf file name, it shows ActionMethod name on the top of the PDF file name in Chrome.
Razor Code:
<iframe src="#Url.Action("GetAgreementToReview", "Employee")" style="zoom: 0.60; -ms-zoom: 1; width: 100%;" width="99.6%" height="420" frameborder="0" id="agreementPdf"></iframe>
CS Code:
public ActionResult GetAgreementToReview()
{
Response.AddHeader("Content-Disposition", "inline; filename=Master-Agreement.pdf");
return File("~/Content/Master-Agreement.pdf", "application/pdf");
}
Image: As you can see in the screenshot, it shows 'GetAgreementToReview' i.e. ActionMethod name instead of 'Master-Agreement.pdf'.
Does anyone know how to fix this issue?
Thanks.
Sanjeev
I had a similar problem and found a solution after exploring almost everything the web has to offer.
You must use a custom route for your action and you must send the filename from UI into the URL itself. (Other parameters won't be affected)
//add a route property
[Route("ControllerName/GetAgreementToReview/{fileName?}")]
public ActionResult GetAgreementToReview(string fileName, int exampleParameter)
{
byte[] fileData = null; //whatever data you have or a file loaded from disk
int a = exampleParameter; // should not be affected
string resultFileName = string.format("{0}.pdf", fileName); // you can modify this to your desire
Response.AppendHeader("Content-Disposition", "inline; filename=" + resultFileName);
return File(fileData, "application/pdf"); //or use another mime type
}
And on client-side, you can use whatever system to reach the URL.
It's a bit hacky, but it works.
If you have an Iframe on HTML to display the PDF (the issue I had), it could look like this:
<iframe src='/ControllerName/GetAgreementToReview/my file?exampleParameter=5' />
And this way you have a dynamic way of manipulate the filename shown by the IFRAME that only uses the last part of an URL for its name shown on the web page (quite annoying). The downloaded filename will have its name given from server-side Content-disposition.
Hope it helps !
please try this code :
return File("~/Content/Master-Agreement.pdf", "application/pdf", "filename.pdf");
Other Helper Link : Stream file using ASP.NET MVC FileContentResult in a browser with a name?

asp.net mobile/desktop site toggle button, switching masterpage, but styles "stuck"

Summary
I'm having style issues when flipping master pages via a button event in asp.net 4.0. The new master switches, but the css from the old master remains. I don't understand how this could happen as the styles are defined within the head of the old master, and i can clearly see via the markup the new master is being displayed with whats supposed to be a totally different set of styles. Also, viewing source shows all the new css declarations in the head. How can i get this to "refresh" or "reload"?
Some details
I'm implementing a mobile version of my asp.net site. If a mobile device is detected i set a cookie and switch the master page in the preinit to a mobile friendly one. This works fine:
protected virtual void Page_PreInit(Object sender, EventArgs e)
{
if (IsMobile)
this.Page.MasterPageFile = "m-" + this.Page.MasterPageFile;
}
I have a "full site" button at the bottom that allows you to flip back and forth between the mobile and desktop view. When clicking it, i change the value in the cookie. Then when the page redirects to itself, the value is checked, and it gives the respective masterpage. This also "works", i can tell the right masterpage is rendering via markup. Except the styles from the mobile version remain even when the desktop master is being displayed. I did the redirect thinking it would prevent this.
// desktop/mobile site toggle button click event
protected void viewMobileButton_Click(Object sender, EventArgs e)
{
HttpCookie isMobileCookie = Cookies.snatchCookie("isMobile");
if (bool.Parse(isMobileCookie.Value))
Cookies.bakeCookie("isMobile", "false");
else
Cookies.bakeCookie("isMobile", "true");
Response.Redirect(Request.RawUrl);
}
This is the first time I've done anything like this, and not sure if i'm even going about it the right way, or how to debug from here. Thanks in advance for any help.
Edit
Ok, so i figured out it's related to the JQuery Mobile Scripts. JQuery Mobile has this way of tying pages together. I don't fully understand it, i think they use it for page transitions, and it's preventing my new CSS from registering. When i turn it off, my masterpage flips fine with css included. I'm looking into a way to turn off JQuery Mobile before my redirect. Note sure how though yet.
The problem ended up being related to JQuery Mobile AJAX for page-transitions. JQuery Mobile does not load the head of the document on additional page requests after the first.
So when i'd switch the mobile master to the desktop master, the head of the document wouldn't load to bring in my styles. There are a few way's this can be fixed:
This way just turns off AJAX altogether, and fixes the problem, but then you can't benefit from it:
<form data-ajax="false">
This is a way to do it problematically, but remind you, it will not work via an event after initialization of JQuery Mobile, so again you can't benefit from it:
$.mobile.ajaxEnabled = false;
The above two solutions i support could work if you redirected through a page first if you have to use an onclick event and an event handler.
A better solution is to add rel="external" to the link to tell JQM it's and outgoing link.
<a href="myself.com?mobile=true" rel="external" >
But because i couldn't run some code i wanted to in order to change the cookie, i had to pass a query string parameter, check it on the preinit, then set the cookie which my page also looks at on the preinit and flips the master.
Here's my full solution below in case someone is out there doing the exact same thing. Note because my website is using aliasing, i had to read Request.RawUrl and parse it myself since the Request.QueryString object did not contain the values i passed.
// reusable function that parses a string in standard query string format(foo=bar&dave=awesome) into a Dictionary collection of key/value pairs
// return the reference to the object, you have to assign it to a local un-instantiated name
// will accept a full url, or just a query string
protected Dictionary<string, string> parseQueryString(string url)
{
Dictionary<string, string> d = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(url))
{
// if the string is still a full url vs just the query string
if (url.Contains("?"))
{
string[] urlArray = url.Split('?');
url = urlArray[1]; // snip the non query string business away
}
string[] paramArray = url.Split('&');
foreach (string param in paramArray)
{
if (param.Contains("="))
{
int index = param.IndexOf('=');
d.Add(param.Substring(0, index), param.Substring(++index));
}
}
}
return d;
}
Then i just use my dictionary object to evaluate and rebuild my url with the opposite mobile value, dynamically setting the href on the toggle link. Some code is obviosuly left out, but for perspective, base._iPage.QueryStringParams hold my dictionary object that was returned, and base._iPage.IsMobile is just a bool property i also have via the page interface i use, that all my pages, and user controls, ect, can talk to.
// get the left side fo the url, without querystrings
StringBuilder url = new StringBuilder(Request.RawUrl.Split('?')[0]);
// build link to self, preserving query strings, except flipping mobile value
if (base._iPage.QueryStringParams.Count != 0)
{
if (base._iPage.QueryStringParams.ContainsKey("mobile"))
{
// set to opposite of current
base._iPage.QueryStringParams["mobile"] = (!base._iPage.IsMobile).ToString();
}
int count = 0;
url.Append('?');
// loop through query string params, and add them back on
foreach (KeyValuePair<string, string> item in base._iPage.QueryStringParams)
{
count++;
url.Append(item.Key + "=" + item.Value + (count == base._iPage.QueryStringParams.Count ? "" : "&" ));
}
}
// assign rebuild url to href of toggle link
viewMobileButton.HRef = url.ToString();
}
Then on my pageinit this is where i actually check, first the quesry string, then the cookie, if neither of those are present, i run my mobile detection method, and set a cookie, and my interface bool property for easy access to conditionals that depends on it.
QueryStringParams = base.parseQueryString(Request.RawUrl);
if (QueryStringParams.ContainsKey("mobile") ? QueryStringParams["mobile"].ToLower().Equals("true") : false)
{
Cookies.bakeCookie("isMobile", "true"); // create a cookie
IsMobile = true;
}
else if (QueryStringParams.ContainsKey("mobile") ? QueryStringParams["mobile"].ToLower().Equals("false") : false)
{
Cookies.bakeCookie("isMobile", "false"); // create a cookie
IsMobile = false;
}
else
{
IsMobile = base.mobileDetection();
}
if (IsMobile)
this.Page.MasterPageFile = "m-" + this.Page.MasterPageFile;
}

Client Callbacks With Master Pages

I'm following this example: http://msdn.microsoft.com/en-us/library/ms178210.aspx
And I can get it to work with just a single page and a code behind, but when I add a masterpage, the examples doesn't work properly. Within my master page, I have a head content section and a body content section. It's nothing fancy.
How do i do client callbacks with master pages?
A more scalable approach would be to use the following syntax (replace the ResultsSpan with an aspx Panel too)...
function LookUpStock()
{
var lb = document.getElementById('<%=ListBox1.ClientID%>');
var product = lb.options[lb.selectedIndex].text;
CallServer(product, "");
}
function ReceiveServerData(rValue)
{
document.getElementById('<%=ResultsSpan.ClientID%>').innerHTML = rValue;
}
This way, if the name (or actual page) of the MasterPage changes the code will still work.
Basically the ASP.NET process parses the page and replaces the <%=%> directives with the correct name of the control on the client.
This approach will also work if you have nested controls. In your example, if you had a control nested inside another panel the rendered id could look something like MASTERPAGEPREFIX_CONTAINERCONTOLNAME_ListBox1 and then your work around would fail.
As a general principle its normally considered a bad idea to "hard code" client side ids in your markup - let the ASP.NET process handle it for you
I got it to work.
Be sure that you amend this code to account for the MasterPage contentId prefix:
function LookUpStock()
{
var lb = document.getElementById("MASTERPAGEPREFIX_" + "ListBox1");
var product = lb.options[lb.selectedIndex].text;
CallServer(product, "");
}
function ReceiveServerData(rValue)
{
document.getElementById("MASTERPAGEPREFIX_" + "ResultsSpan").innerHTML = rValue;
}

Passing arguments from one asp.net page to another using jQuery

I need to pass 4 arguments (3 strings and one comma separated list) from an ASP.NET page to another ASP.NET page using jQuery. The destination page ought to be launched as a separate window, which works fine with the following jQuery snippet:
$('#sourcePageBtn').click(function(){
window.open("destinationPage.aspx");
return false;
});
How can I pass the arguments to the destination page? I am trying to avoid the query string to pass the arguments because:
I don't want to show the url arguments (which can also be very long) in the destination window.
There are some special characters like ',/,\, & etc. in the string arguments.
Please suggest.
Edit:
I'm trying to access the arguments in the script section of the aspx file i.e.
<script language="C#" runat="server">
protected void Page_Load ( object src, EventArgs e)
{
//Creating dynamic asp controls here
}
</script>
My specific need for the arguments in the Page_Load of the script section stems from the fact that I am creating a few dynamic Chart controls in the Page_Load which depend on these arguments.
cheers
Initial Thoughts (before solution created)
Use POST for large data instead of GET. With POST no querystring will be used for data and therefore URL length restriction isn't a concern. (The max URL length differs between browsers so you're right to stay away from it when large data is moving).
Special URL characters can be encoded to be passed in the query string so that shouldn't be an issue.
Alternatively you might store the data on the server side from the first page, and have the second page pick it up from the server side. But this is overkill. And it makes you do unneeded server programming.
Passing state via HTTP calls is standard practice. You shouldn't try to circumvent it. Work with it. All the facilities are built in for you. Now it's just up to jQuery to provide us some help...
Note: Be careful using jQuery for main app features in case JavaScript is disabled in the browser. In most cases your web application should be usable at a basic level even when JavaScript is disabled. After that's working, layer on JavaScript/jQuery to make the experience even better, even awesome.
Edit: Solution (with ASP.NET processing)
Key resources for solution implementation are:
How use POST from jQuery - initiates the request, passes arguments, gets response
jQuery context argument - this is how the popup window DOM is accessed/affected from the main window
How it works: From a main page, a POST occurs and results are displayed in a popup window. It happens in this order:
The main script opens a popup window (if it doesn't already exist)
main script waits for popup window to fully initialize
main script POSTs (using AJAX) arguments to another page (sends a request)
main script receives response and displays it in the popup window.
Effectively we have posted data to a popup window and passed arguments to the processing.
Three pages follow and they constitute the complete solution. I had all 3 sitting on my desktop and it works in Google Chrome stable version 3.0.195.38. Other browsers untested. You'll also need jquery-1.3.2.js sitting in the same folder.
main_page.html
This is the expansion of the logic you provided. Sample uses a link instead of a form button, but it has the same id=sourcePageBtn.
This sample passes two key/value pairs when the POST occurs (just for example). You will pass key/value pairs of your choice in this place.
<html>
<head>
<script type="text/javascript" src="jquery-1.3.2.js"></script>
</head>
<body>
<a id="sourcePageBtn" href="javascript:void(0);">click to launch popup window</a>
<script>
$(function() {
$('#sourcePageBtn').click( function() {
// Open popup window if not already open, and store its handle into jQuery data.
($(window).data('popup') && !$(window).data('popup').closed)
|| $(window).data('popup', window.open('popup.html','MyPopupWin'));
// Reference the popup window handle.
var wndPop = $(window).data('popup');
// Waits until popup is loaded and ready, then starts using it
(waitAndPost = function() {
// If popup not loaded, Wait for 200 more milliseconds before retrying
if (!wndPop || !wndPop['ready'])
setTimeout(waitAndPost, 200);
else {
// Logic to post (pass args) and display result in popup window...
// POST args name=John, time=2pm to the process.aspx page...
$.post('process.aspx', { name: "John", time: "2pm" }, function(data) {
// and display the response in the popup window <P> element.
$('p',wndPop.document).html(data);
});
}
})(); //First call to the waitAndPost() function.
});
});
</script>
</body>
</html>
popup.html
This is the popup window that is targeted from the main page. You'll see a reference to popup.html in the jQuery script back in the main page.
There's a "trick" here to set window['ready'] = true when the popup window DOM is finally loaded. The main script keeps checking and waiting until this popup is ready.
<html>
<head>
<script type="text/javascript" src="jquery-1.3.2.js"></script>
</head>
<body>
<!-- The example P element to display HTTP response inside -->
<p>page is loaded</p>
</body>
<script>
$(function() {
window['ready'] = true;
});
</script>
</html>
process.aspx.cs (C# - ASP.NET process.aspx page)
The dynamic server page the arguments are POSTed to by the main page script.
The AJAX arguments arrive in the Page.Request collection.
The output is delivered back as plain text for this example, but you can customize the response for your apps requirements.
public partial class process : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
// Access "name" argument.
string strName = Request["name"] ?? "(no name)";
// Access "time" argument.
string strTime = Request["time"] ?? "(no time)";
Response.ContentType = "text/plain";
Response.Write(string.Format("{0} arrives at {1}", strName, strTime));
}
protected override void Render(System.Web.UI.HtmlTextWriter writer) {
// Just to suppress Page from outputting extraneous HTML tags.
//base.Render(writer); //don't run.
}
}
Results of this are displayed into the popup window by the original/main page.
So the contents of the popup window are overwritten with "[name] arrives at [time]"
Main References: HTTP Made Really Easy, jQuery Ajax members and examples.
If you keep a reference to the new window when you open it, ie var destWin = window.open(...) then you can access the variables and methods on the destWin window object. Alternatively you can "reach back" from the destination window with window.opener.

Resources