Page.ParseControl to find HTMLImage - asp.net

I have a richtext textbox on a webpage that will be used to create email templates. This textbox returns HTML as a string. I need to get the source of all the images from the HTML so that the images can be stored in the database. Once the HTML is returned the images have already been loaded to the server and the new path has been used as the source of the image.
I would like to parse the controls, loop through the controls as seen below, find the images save to the database and change the source to a new value.
However when the string is parsed, it always returns one literal control unless there is a runat server attribute assigned to the tag. If the run at server is present it correctly identifies the control as an HTMLImage control.
Is there away to get the page to parse all the controls regardless of if they are server controls?
Dim s As String = "<P><IMG src=""http://localhost/MessageImages/14699666.jpg""></P>"
Dim cnts As Control = Page.ParseControl(s)
For Each c As Control In cnts.Controls
If TypeOf c Is System.Web.UI.HtmlControls.HtmlImage Then
Dim src As String = CType(c, HtmlImage).Src
'TODO: Save image to database
'TODO: Change source
End If
Next

It sounds to me like you'd be better of using something like the HTML Agility Pack to parse the raw HTML from the editor instead. As it works with the pure HTML you don't need to worry about whether controls are server controls or HTML controls etc.

Related

Display an image from a Byte Array from SQL into an ASPX page that is currently routed

I have the most convoluted and headache of a way to attempt to load am image on a page. I am using VB.Net, my page is routed from a Routes.XML document, I have a SQL database with images stored as varbinary(MAX) fields, I need to load said images from the page into an control, and everything that i use to use will not work with the routing.
If you need to see code examples let me know, but I was wondering if anyone knew of a way to display an image from bytes in this fashion.
use this code:
Dim Ph As Byte()
Ph = DirectCast(YourImageFromDB), Byte())
Dim img As Image = Nothing
Dim stream = New MemoryStream(Ph)
img = Image.FromStream(stream)
Ended up having a friend show me how he routed with images. What basically happens is that I needed to create an ASHX file to create the image, and put the full path from the image.ashx that I create as the URL I need. Worked like a charm. First time ever working with a handler file so i had no idea how to use it at first.

Header.Stylesheet.CreateStyleRule on partial postback

I've recently added an UpdatePanel to a single webpage which renders different usercontrols on button clicks. I'm struggling with a problem where i'm adding inline styling into the header dynamically with Header.Stylesheet.CreateStyleRule - the problem is that it doesn't get inserted on partial postbacks and it does make sense. This is obviously because it's a partial postback and the header is only being rendered when the page loads the first time.
The styling is being added by the following methods, which gets the styling from a database:
Private Sub InitializeStylesheet(ByVal ButtonId As Integer)
Dim CSSStylesheet As Stylesheet = StyleBackend.GetStylesheets(ButtonId)
Dim IdClassList As List(Of StyleIDClass) = StyleBackend.GetStylesheetsStyleIDClass(CSSStylesheet.StylesheetID)
'Iterates through the cssidclass
For Each cssidClass In IdClassList
Dim styleItems As List(Of StyleItem) = StyleBackend.GetStyleItemsByIDorClass(cssidClass.StyleIDClassID)
Dim cssString As String = Nothing
For Each StyleItem As StyleItem In styleItems
cssString += StyleItem.Property & ":" & StyleItem.Value & ";"
Next
'Iterates all cssitems which belongs to a cssidclass
Me.Header.StyleSheet.CreateStyleRule(New CustomStyle(cssString), Nothing, cssidClass.ClassOrID)
Me.Header.ViewStateMode = UI.ViewStateMode.Disabled
Next
End Sub
I've been googling my ass off trying to get this to work, but it seems to be impossible.
This msdn article literal says that it is impossible to do what i'm trying to do.
http://msdn.microsoft.com/en-us/library/system.web.ui.htmlcontrols.htmlhead.stylesheet.aspx
Adding styles or style rules programmatically during asynchronous postbacks is not supported. When you add AJAX capabilities to an ASP.NET Web page, asynchronous postbacks update regions of the page without updating the whole page. For more information, see Microsoft Ajax Overview.
Does anyone have a suggestion or alternative way of doing this?
Thank you!
One solution is just to include the styles in your main stylesheet(s) rather than modifying them dynamically. Even if they are data-driven, you could output them with the main page via an HTTP handler if the total list isn't too large.
Alternatively (and probably more efficiently), you can return the style data to the client as a string and process it there.
You can listen for the EndRequest event on the client script manager:
function endRequest(){
// look at the updated DOM
}
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);
Perhaps the following sequence:
Initiate async postback
Render the styles to a hidden field inside the UpdatePanel
On endRequest, examine the DOM to see if it contains a hidden field with styles (based on naming convention, data attributes, or just ID)
Grab the values out of the hidden field and add them to the page's style rules using JavaScript

Rendering of asp.net controls

I find it hard when using asp.net controls, to make proper css files because I don't know what the html output for the different controls end up as.
For example, if I want to add a div tag using a asp.net control, it's not easy to know what kind of control I can use.
Are there any documentation that shows for each asp.net control, what the rendered html for that control will be? I understand that some controls will probably change it's output due to how it's configured, but most controls will at least follow a pattern here.
The best would of course be a service on the web where you can put in the asp.net control definition and get the rendered html out.
Currently I have to put a control into my webform, run it and check the source in the browser, and if it's not the correct html tag, try another control and repeat. That get's tedious quite fast.
If you want to know to what html-controls a server-control is rendered, you could call RenderControl:
Dim myGridView as new GridView
Dim sb as New StringBuilder()
Dim sw as New IO.StringWriter(sb)
Dim textWriter as New HtmlTextWriter(sw)
myGridView.RenderControl(textWriter)
' now we can have a look what asp.net has rendered: '
Dim gridViewHTML as String = sb.ToString()
The rendered html will even differ from browser to browser for example when ASP.Net thinks the client uses a "lower"-browser(BrowserCaps), a Panel will be rendered as Table instead of a DIV.
By the way, if you're testing my above code on controls inside of your page, you have to override VerifyRenderingInServerForm otherwise you get a "...must be placed inside a form tag with runat=server"-error:
Public Overrides Sub VerifyRenderingInServerForm(ByVal control As System.Web.UI.Control)
Return
End Sub
I would recommend adding a CssClass to your WebControls, and doing all your styling using classes, rather than HTML element types. As Tim Schmelter says, the html can render differently for different clients (I seem to remember a Panel can be a span as well under certain circumstances).
To avoid actually having to add the CssClass each time, you can subclass the WebControl you want, then set it's CssClass in Control_Init.

Assign database value to hyperlink but not a runat=server

Its simple if I have an ASP.net page with an ASP.net linkbutton / hyperlink
and I obtain a value from say a SQL Database and I store it in the label...
For example:
this.myLabel.Text = someValueReturnedFromADatabase
This is simple because it goes right to the code behind page and set the text value
to the value returned from my database (aside from going into more details with data access layer, etc).
What I was wondering is what if I dont want to use an ASP.net linkbutton and I simply want to use an HTML link button (as I need to call the jquery fade function). How would I set the value someValueReturnedFromADatabase to a control that is not runat=server?
Have a variable in your codebehind:
protected string TextForLabel
Set it in Page_Load, or wherever:
TextForLabel = someValueReturnedFromADatabase;
Reference it with pointy-bracket percent notation:
<% =TextForLabel %>
You can set runat="server" on standard html controls. I do it all the time. Then you will be able to access their properties in your code behind just like you do for asp controls.
If I am not mistaken, for labels you can use .InnerText or .InnerHTML to change the text.
From what I know of, you need to make some sort of relation between your HTML document and the code behind to interact with data from a SQL database. Either that or you'll have to make the entire database connection etc. in the HTML header using script type="text/javascript" and script type="text/C#" or whatever language you use to develop.

ASP.NET Parsing raw HTML into Controls

Is it possible in ASP.NET to take a string containing some HTML and make ASP.NET to parse it and create a Control for me? For example:
string rawHTML = "<table><td><td>Cell</td></tr></table>";
HTMLTable table = MagicClass.ParseTable(rawHTML);
I know that this is a bad thing to do but I am in the unfortunate situation that this is really the only way I can achieve what I need (as I cannot modify this particular coworker's code).
Also, I know that LiteralControl allows you to have a control with arbitrary HTML in it, but unfortunately I need to have them converted to proper control.
Unfortunately, HTMLTable does not support the InnerHTML property. I need to preserve the HTML tree exactly as it is, so I cannot put it into a <div> tag.
Thanks.
The closest I think you'll get is Page.ParseControl, which is the ASP.NET parser. The downside is that the text you have is a LiteralControl, since it doesn't have runat="server" on it - so you 'll do a very tiny bit of string manipulation beforehand.
In otherwords:
this.ParseControl("<table><tr><td>Cell</td></tr></table>")
will produce:
Control
LiteralControl
whereas:
this.ParseControl("<table runat=\"server\"><tr><td>Cell</td></tr></table>")
will produce:
Control
HtmlTable
HtmlTableRow
HtmlTableCell
LiteralControl
You could traverse the HTML string a token at a time (token defined here as HTML Element or HTML InnerText), and determine which control needs to be instantiated, and what attributes it needs. But, that would be something highly... evil in the writing.
Why exactly do you need it to be a "proper" control as opposed to a text inside of a Literal control?

Resources