Using HTML5 file (Multiple) control in asp.net - c#

I am looking for a way to perfectly manage the <input type="file" multiple="multiple"> tag of HTML 5 in my asp.net 3.5 project.
I have done it before with a single control on page, but what if we have multiple upload controls on the same page. Please see my code:
protected void btnSave_Click(object sender, EventArgs e)
{
//---------Need to check if my upload control has files: Please suggest a perfect way
if (fupAttachment.PostedFile != null || fupAttachment.PostedFile.FileName != "" || fupAttachment.PostedFile.ContentLength>0)//here is a problem, as it does not checks for a blank file upload control
HttpFileCollection hfc = Request.Files;
string strDirectory = Server.MapPath("~/") + "Mailer/" + hidCampID.Value;
if (hfc.Count>0)
{
if (!System.IO.Directory.Exists(strDirectory))
{
System.IO.Directory.CreateDirectory(strDirectory);
}
if (System.IO.Directory.Exists(strDirectory))
{
for (int i = 0; i < hfc.Count - 1; i++)
{
hfc[i].SaveAs(strDirectory + "/" + hfc[i].FileName.Replace(" ", "_"));
}
}
}
}
}
My asp page is something like this:
//----this control is from which I want to multiple upload files
<input type="file" multiple="multiple" runat="server" id="fupAttachment" />
// Another upload control is there which takes input when page loads
<asp:FileUpload ID="fupMailingList" runat="server" />
So, exactly my problem is that when page loads "fupMailingList" has taken a file, and then when I want to use my multiple upload control "fupAttachment", I am unable to check if it has any files or not, as hfc checks for all upload controls and it gets file in one of them. So, please tell me a way to check only "fupAttachment" control and then do my work correctly.

Rather than iterating over all the files in the request, you should check on a per input basis.
var uploadedFiles = Request.Files.GetMultiple("fupAttachment");
if(uploadedFiles.Count > 0)
{
//
}

Just check the HasFile property.
if(fupMailingList.HasFile){
//Do something
}

Related

Convert panel HTML to PDF using C# ASP.NET

I have a basic form with mostly textboxes and a few checkboxes and radio buttons. Pretty much when a user fills it out and hits submit, I need it to convert and display a PDF with the same structure and offer a print option. I have searched online and I have tried most of the options but nothing works.
I don't expect this to be too difficult, but I am fairly new to C# and can't figure out how to make an HTML panel into a PDF and print it. Any help would be appreciated, thanks in advance!
Here is the HTML for one of the labels and textboxes and the submit button:
<div>
<asp:Label ID="lblDate" runat="server" Text="Date:"></asp:Label>
<asp:TextBox ID="txtDate" runat="server"></asp:TextBox>
</div>
<asp:Button ID="SubmitButton" runat="server" Text="Button" OnClick="btnSubmit"/>
Once clicked, the .cs page will go through this:
litDate.Text = "Date: " + txtDate.Text + "<br />";
and update the panel to display the value:
<asp:Panel ID="PDFPanel" runat="server" Visible="false">
<asp:Literal ID="litDate" runat="server"></asp:Literal>
</asp:Panel>
I am not sure if the panel is needed, but this is how I was able to be sure I was getting the value back. Is there a way to go straight from submit to PDF and print?
Use something like http://code.google.com/p/wkhtmltopdf/
This roughly outlines how to do it: https://stackoverflow.com/a/18767473/181771
I made an asp.net website demo taking the contents of a panel or div and generating a pdf from the html. This is using NReco.PdfGenerator (another wkhtmltopdf wrapper):
https://github.com/jay8anks/Asp.net-HtmlToPdf_NReco.PdfGenerator
Yeah, it's a webform, but anyone sharp enough to do mvc should be able to adapt it fairly easily.
Basically, it is using javascript to get the html between a panel (div) tag and store it in a hiddenfield. Pretty straight forward, except if you want to have css or images, you can't use a relative url for them. I actually just embedded the css inline as a string, but there are other ways of doing it.
Then in the codebehind, this gets the html and generates a pdf from it:
protected void SaveHtmlToPdf()
{
string htmlOutput = Server.UrlDecode(HiddenField1.Value);
htmlOutput = string.Join(" ", System.Text.RegularExpressions.Regex.Split(htmlOutput, #"(?:\r\n|\n|\r|\t)"));
htmlOutput = htmlOutput.Replace("\"", "'");
string headerStyle = HeaderStyle();
string finalHtml = headerStyle + htmlOutput;
var strWr = new StringWriter();
var htmlWr = new HtmlTextWriter(strWr);
// base.Render(htmlWr);
var htmlToPdf = new HtmlToPdfConverter();
string filename = (orderId + ".pdf");
string filepath = "~/sales_pdfs";
string combinedFilePath = Path.Combine(Server.MapPath(filepath), filename).ToString();
for (int i = 1; i <= NumberOfRetries; ++i)
{
try
{
htmlToPdf.GeneratePdf(finalHtml, null, combinedFilePath);
break; // When done we can break loop
}
catch (IOException e)
{
// You may check error code to filter some exceptions, not every error
// can be recovered.
if (i <= NumberOfRetries)
{
Thread.Sleep(DelayOnRetry);
}
ltMsg.Text = "There was a problem creating the PDF";
}
}
}
This puts a pdf in a directory so it can be downloaded, but there are other ways that could be handled, as well. We actually wanted a copy of the PDF that someone was generating, so this was the direction we went in.

C# - Sending value to HREF in html

I have written a project in C# in which I load a HTML webpage if an event occurs during teh course of the project usage.
My issue is that inside my html page, I have a href node inside a tag as such:
<a href="http://pseudo01.hddn.com/vod/demo.flowplayervod/flowplayer-700.flv"
style="display:block;width:inherit;height:inherit;background-color: black;overflow:hidden"
id="player">
</a>
I would like to change the href value programatically by sending a C# variable (called myHrefFile) depending on what the user did.
How can this be done?
you can do something like this
<a href="<%= someMethodThatGetHrefValue() %>"
style="display:block; width:inherit;height:inherit; background-color:black;
overflow:hidden"
id="player">click</a>
call the method that decide what should be href for link .
and put all the logic of deciding href in that method like this
public string someMethodThatGetHrefValue()
{
if(someval == true)
return "http://www.google.com";
else
return "http://www.yahoo.com";
}
Something like this perhaps? This is an Asp.net solution.
<asp:LinkButton ID="LinkBut" runat="server" onclick="LinkBut_Click">Click here</asp:LinkButton></p>
protected void LinkBut_Click(object sender, eventArgs e)
{
string myHrefFile = "";
if(Value.equals(true))
{
myHrefFile = "page1.aspx";
}
else
{
myHrefFile = "page2.aspx";
}
Response.Redirect(myHrefFile );
}

How to check if ContentPlaceHolder is empty?

How to check if ContentPlaceHolder is absolutely empty?
In the ContentPlaceHolder have text only, without tags and controls.
Example Page.Master:
<asp:ContentPlaceHolder runat="server" ID="Content" />
Example Test.aspx:
<asp:Content runat="server" ContentPlaceHolderID="Content">
Custom text without controls. Content.Controls.Count is 0 and Content.HasControls is false.
</asp:Content>
What I need to do is that when the placeholder is empty put a default content is in another control.
Overwrite tried twice for the same placeholder but I get error when dynamic load.
You can implement a method that will render the content control into a string, then check the string to find wheahter it contains any non-white space chars:
private bool HasContent(Control ctrl)
{
var sb = new System.Text.StringBuilder();
using (var sw = new System.IO.StringWriter(sb))
{
using(var tw = new HtmlTextWriter(sw))
{
ctrl.RenderControl(tw);
}
}
var output = sb.ToString().Trim();
return !String.IsNullOrEmpty(output);
}
protected void Page_PreRender(object sender, EventArgs e)
{
var placeholder = Master.FindControl("FeaturedContent");
var hasContent = HasContent(placeholder);
}
You need to find the ContentPLaceHolder on the master page first. Then you can cast the first control(which always exists) to LiteralControl and use it's Text property.
So this works as expected from Page_Load of the content-page:
protected void Page_Load(object sender, EventArgs e)
{
var cph = Page.Master.FindControl("Content") as ContentPlaceHolder;
if (contentPlaceHolder != null)
{
string textualContent = ((LiteralControl) cph.Controls[0]).Text;
if (string.IsNullOrEmpty(textualContent))
{
// ...
}
}
}
This seems to have changed, because I am seeing in 4.5 that HasControls DOES return true when there is only literal text in the Content, even a single whitespace. I do something like this in my master page:
<asp:Panel id="SidebarPanel" CssClass="Sidebar" runat="server">
<asp:ContentPlaceHolder id="SidebarContent" runat="server" />
</asp:Panel>
Sub Page_Load(...)
SidebarPanel.Visible = SidebarContent.HasControls
End Sub
This renders the sidebar content, if there is any, inside a <div class="Sidebar"> -- and avoids creating an empty div on the page when there's no content.
I really didn't want to run all the code for a render or risk that maybe some controls might have states that change after being rendered. So I came up with another approach.
public static int ChildrenCount(ContentPlaceHolder placeholder)
{
int total = 0;
total += placeholder.Controls.OfType<Control>().Where(x =>
(!(x is ContentPlaceHolder) && !(x is LiteralControl)) ||
(x is LiteralControl && !string.IsNullOrWhiteSpace(((LiteralControl)x).Text))
).Count();
foreach (var child in placeholder.Controls.OfType<ContentPlaceHolder>())
total += ChildrenCount(child);
return total;
}
For me the text I'd place directly into a Content element would be returned by OfType as a LiteralControl with the appropriate contents. Not only this but my formatting ("\r\n\t") would also be returned the same way. I'd also get ContentPlaceholders for subsequent master pages as they passed the slot in my web pages to the next master page or actual page.
So the task now is to get a count of controls that excludes these ContentPlaceholders and also excludes LiteralControls which are whitespace. This is pretty easy using the is operator. We'll just make sure a given control is neither of those types and then count it, or if it is a Literal we check if the contents are all whitespace or not. The last step is to recursively add the results of the same operation for all child ContentPlaceholders so nested master pages work as expected.
And then finally:
if (ChildrenCount(MyContentPlaceholder) == 0)
MyContentPlaceholder.Controls.Add(new LiteralControl("My default content!"));
My 2 cents:
If it's a constant content you'll have to insert AND there will be no <Content> at all:
<asp:ContentPlaceHolder>
<!-- Anything here will be inserted if there's no Content -->
</asp:ContentPlaceHolder>

How to create custom control of existing user control

I have created one user control for multiple file upload ,
i need to create its custom control so that I can have a dll of that control.
What are the ways that I can do this?
usercontrol.ascx
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.MultiFile.pack.js" type="text/javascript"></script>
<div><%-- accept attribute can be used like accept="png|jpg"--%>
Multiple File Upload<br />
<asp:FileUpload ID="FileUpload10" runat="server" class="multi" accept="" />
<asp:Button ID="Button3" runat="server" Text="Submit" OnClick="jQueryUploadFiles" />
<br />
<asp:Label ID="lblMessage" runat="server" EnableViewState="false" ForeColor="Green" />
<br />
<asp:Label ID="lblError" runat="server" EnableViewState="false" ForeColor="Red" />
</div>
usercontrol.ascx.cs
private void FileUploadUsingJQuerySelectionMethod()
{
// check if file has been selected
HttpFileCollection files = Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFile file = files[i];
if (file.ContentLength > 0)
{
string path = ConfigurationManager.AppSettings["FilePath"];
string fileName = Path.GetFileName(file.FileName);
// now save the file to the disk
file.SaveAs(path + fileName);
lblMessage.Text += "File : <b>" + fileName + "</b> uploaded successfully !<br />";
}
}
}
I tried like following:
public class MultipleFileUpload : WebControl
{
#region declare controls here
Label lblMessage;
Label lblError;
FileUpload FileUpload10;
Button btnUpload;
#endregion
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string FilePath
{// prop to get filepath
get
{
String s = (String)ViewState["FilePath"];
return ((s == null) ? "[" + this.ID + "]" : s);
}
set
{
ViewState["FilePath"] = value;
}
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(FilePath);
}
// create the layout (html) of your control here
// all the HTML code including <div>
// Add all controls to the <div>, below code is very crude.<br/>
// Also you need to register the script tags and add the script to it<br/>
protected override void CreateChildControls()
{
base.CreateChildControls();
Table table = new Table();
this.Controls.Add(table);
lblMessage = new Label();
lblMessage.ID = "lblMessage";
lblError = new Label();
lblError.ID = "lblError";
FileUpload10 = new FileUpload();
FileUpload10.ID = "FileUpload10";
btnUpload = new Button();
btnUpload.ID = "btnUpload";
btnUpload.Text = "Submit <br/> ";
// table.Controls.Add(lblMessage);
}
// invoke this method were ever required
private void FileUploadUsingJQuerySelectionMethod()
{
// check if file has been selected
HttpFileCollection files = HttpContext.Current.Request.Files;
for (int i = 0; i < files.Count; i++)
{
HttpPostedFile file = files[i];
if (file.ContentLength > 0)
{
string path = FilePath;
string fileName = Path.GetFileName(file.FileName);
// now save the file to the disk
file.SaveAs(path + fileName);
lblMessage.Text += "File : <b>" + fileName + "</b> uploaded successfully !<br />";
}
}
}
You can put your control in a dll following the steps detailed here: Turning an .ascx User Control into a Redistributable Custom Control.
I think that it would be worth converting your user control to a proper server control, however, it's not that hard and you would end up with easier to maintain code (as you will see, the process described there is rather awkward).
You could add the js files by embedding them in the dll i.e.
Including them as normal in the custom control project
Right clicking and selecting 'embedded resources'
Accessing through the resource manager as they are now part of the default resource file i.e.
Stream ms = Assembly.GetExecutingAssembly()
.GetManifestResourceStream("resourcename including namespace");
Then read the stream to get the script as a string
Register the script string with ScriptManager in the usual way
To build a web control you need to inherit from UserControl or another control, in your case FileUpload, then override the init event to add other controls (e.g. button) to the tree. Override any other events as needed.
Old article but pretty clear e.g. of principal:
http://www.codeproject.com/KB/validation/textboxwithvalidator.aspx

How to access span with needed innerhtml?

Say my WebBrowser1 downloaded a page that has a following line:
<span customattr="hamolulu">hamolulu</span>
It is inside of a td tag, inside of big table, inside of iFrame, inside of div etc.
How to I click this thing using c# ?
I need to do something following:
int i = 0;
for (i = 0; i <= 500; i++)
{
if (webBrowser1.Document.GetElementsByTagName("span")[i].GetAttribute("customattr") == "hamolulu")
{
webBrowser1.Document.GetElementsByTagName("span")[i].InvokeMember("click");
break;
}//end if
}// end for
but for some reason it does not work this way, so I'm thinking if it's possible to check the innerHTML of the span, or innerText?
I tried both:
webBrowser1.Document.GetElementsByTagName("span").InnerHTML == "hamolulu"
webBrowser1.Document.GetElementsByTagName("span").InnerText == "hamolulu"
And I failed both times.
Update:
I just noticed that the line is actually like this:
<span customattr="hamolulu"><a>hamolulu</a></span>
So I wrote a simple function:
int i = 0;
for (i = 0; i <= webBrowser1.Document.GetElementsByTagName("a").Count - 1; i++)
{
log(i.ToString()+ " : " +webBrowser1.Document.GetElementsByTagName("a")[i].InnerHtml);
} //log(string) is a custom function that saves all strings to a file log.txt
And what I've seen is that this link (and span) does not show up in my log.
In other words, getElementsByTagName("span") and getElementsByTagName("a") doesn't see the item. My guess is that it is because of iFrame. Do you have any thoughts about this?
another solution using no js (because you don't own the "page")
since it is inside an iframe then you should search within that iframe
HtmlElementCollection iframes = WebBrowser1.Document.GetElementsByTagName("iframe");
HtmlElement iframe = iframes(0 /* iframe index */); //
HtmlElementCollection spans = iframe.Document.GetElementsByTagName("span");
for (i = 0; i < spans.Count; i++) {
HtmlElement span = spans(i);
if (span.GetAttribute("customAttr") == "customAttrValue") {
string onclick = span.Children(0).GetAttribute("onclick"); //span.Children(0) should return the <a>
WebBrowser1.Document.InvokeScript(onclick);
}
}
Unless I am missing something...
<span id="hamolulu">hamolulu</span>
Then when you want to change it...
document.getElementById('hamolulu').innerHTML="<h1>Test!</h1>";
If you set up your span as an HTML server control:
<span runat="server" id="myspan" customattribute="customvalue">hello world</span>
Then you can register an event handler on page load:
protected void Page_Load(object sender, EventArgs e)
{
myspan.Attributes["onclick"] = "this.innerText='hamolulu'";
}
Another way to do it is using Page Methods which would call a page C# method using AJAX.
you can make it simpler by using JavaScript and invoking it from c# whenever you need to.
WebBrowser1 .Document .InvokeScript ("functionName")
javascript:
function functionName(){
var spans = document.getElementsByTagName('SPAN');
for (i = 0; i < spans.length; i++)
{
var span = spans[i];
if (span.getAttribute("customattr") == "hamolulu")
{
eval(span.getAttribute('onclick')); // .. be careful "span" has no "click()" method. you should use the onlick attribute if available
break;
}//end if
}// end for
}

Categories

Resources