Set background-url css property to a memory image in .net - asp.net

Please read about my following situation. So we have a web application in .net. Because some customers wanted to pay for some custom layout, we first started to use themes. It was ok until there were more than 10. Because after that it was difficult to maintain and more of them wanted custom design, I had to design a solution so that the user could change only a few css attributes through a front-end page.
So when a user clicked a button a folder with its name and another css file was generated and he could change the attributes and save the new file. This file was dynamically loaded on the Page_Load on some basebage. This was ok, until more and more users payed for this and now we have tens of folders and expect hundreds. There is also the problem of rights, by default IIS doesn't have writing right to the application folder. Also the deployment process builds a new version by deleting the whole app folder and recreating one so we had to do a workaround and make a copy of this mega folder that holds the users css. And anyway, I don't like the idea of having hundreds of files not under source control.
And now, I have a new requierement. The users to be allowed to upload a custom image to replace one of our own. So i said it is time to move evrything to the database. For basic attributes I solved it.
I have a "mutant" aspx page:
<%# Page Language="C#" ContentType="text/css" %>
.labelText
{
color:<%= WebApplication1.UserProfile.LabelColor%>
}
So the UserProfile class gets it's data from a table.
And then in the page_load of the basepage
HtmlLink link = new HtmlLink();
link.Attributes.Add("type", "text/css");
link.Attributes.Add("rel", "stylesheet");
link.Attributes.Add("href", "~/Styles/Override.aspx");
this.Header.Controls.Add(link);
It works ok, the problem the images are used like this:
.divHeader
{
background: 15px 0 url("logo.gif")
}
That logo.gig will be uploaded by the user,but I would like to be saved in the database. However when reading it as a stream I can't do something like:
background: 15px 0 url(WebApplication1.UserProfile.Logo)
Is there any otehr way I can specify an object in a css class?If it isn't what is the best approach? I was thinking about keeping the image in the db and also as a file, something similar to what we have now.
I realize that if it were for an image control it would have been a lot easier, but this is the design now, and remaking it is a little bit troublesome
Thanks for reading this novel and for any oppinions on this.

I hope you're saving the mime-type value of every image that you save to database (mime type is reported by the request during upload). If you don't, you'll have to look up what a mime type would be based on image-file extension or its content format. You'll need this value when images are requested (from within CSS files).
Implement an HTTP handler (.ashx) specifically for these images (new file > generic handler > fill up ProcessRequest).
Then, replace url(logo.gif) in your css files with something like this:
url(/GetImage.ashx?user=1234&image=logo);
Obviously, you can have the filename and query to be whatever you like/need. Maybe you have user info in session, so you don't have to include user id there. Maybe you'll want to implement this handler only for logo images, and if you have user info in session, you can simply say (css):
url(GetLogo.ashx);
Then, within that ashx handler, write code to get the image from the database (or where ever it is), and stream it to the browser. Something like this:
byte[] imageData = ... // get this from db
MemoryStream ms = new MemoryStream(imageData); // System.IO namespace
Response.ContentType = "image/png"; // remember the mime-type?
ms.WriteTo(context.Response.OutputStream); // context is current HttpContext
Alternatively, you can inject the whole image into the CSS, by encoding it to base-64 format. Note that the size of css file will grow for the size of the image, and you're practically combining multiple downloads into 1, which may be a good or a bad thing.
Example below (google's logo); paste this in CSS (notice the size of that thing).
Besides CSS, the data in this example (data:image/png;base64,iVBORw0KGg ...) can be used as URL with IMG tags, or manipulated by JS.
.somediv
{
width:275px;
height:95px;
background-image: url(data:image/png;base64,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);
}
+1 if you like this :)

Related

Update all links on page before returning page to client

Overview
We have an in house CMS that we've recently added multilingual support to. The CMS allows dragging/dropping of various panels (.net controls) and some panels show dynamic content entered via a rich text editor. Also, some fields are multilingual so some panel content will change according to the current language.
Ideally we want to add the language to the URL. So /contact-us becomes /en/contact-us.
Our main handler will then set the language and the all panels will show relevant copy.
Goal
So, ideally we'd like to be able to:
Process the page server side after it's been built by our main page assembler (eg in PreRender)
Parse the built page or recurse the control tree to update ALL internal links
Prepend a lanauge code to all internal links on the page. (easy enough once we know where they all are)
NB: Some links will by in .net HyperLink controls but others will be <a> tags entered via a Rich Text Editor.
Stuff I've looked at
I've skimmed google but haven't found anything that seems to match our needs:
Html Agility Pack - can be used to take a URL and parse for links. But I'm guessing this can't be used say in Pre_Render of our main page builder. Ideal for scraping I suppose.
Various JS solutions - locate links and update. Very easy but I'm wary of using JS for updating URLs client side.
All suggestions welcome :)
So, There will be dynamic content and static content. And the CMS users should be able to edit both of them. You should have a Language DB table, and for instance; For "about us" page, There should be about-us EN, about-us DE, about-us FR rows in other table.
And you should have another table for static content. For instance for contacy us form. There are static texts on contact forms. Name, e-mail,message etc.
This can be done by overriding Page.Render() as follows:
protected override void Render(HtmlTextWriter htmlWriter)
{
StringBuilder ThisSB = new StringBuilder();
StringWriter ThisSW = new StringWriter(ThisSB);
HtmlTextWriter RenderedPage = new HtmlTextWriter(ThisSW);
// pass our writer to base.Render to generate page output
base.Render(RenderedPage);
// get rendered page as a string
string PageResult = ThisSB.ToString();
// modify the page
string ModifiedPage = UpdatePage(PageResult);
// write modified page to client
htmlWriter.Write(ModifiedPage);
}
The method UpdatePage can manipulate the page as a string in any way you wish - in our case we use find and update all links and local file paths.

Can not display base64 encoded images in an HTML fragment in WinJS app

I'm writing a WinJS app that takes an HTML fragment the user has copied to the clipboard, replaces their
Later, when I go to display the .html, I create an iFrame element (using jQuery $(''), and attempt to source the .html into it, and get the following error
0x800c001c - JavaScript runtime error: Unable to add dynamic content. A script attempted to inject dynamic content, or elements previously modified dynamically, that might be unsafe. For example, using the innerHTML property to add script or malformed HTML will generate this exception. Use the toStaticHTML method to filter dynamic content, or explicitly create elements and attributes with a method such as createElement. For more information, see http://go.microsoft.com/fwlink/?LinkID=247104.
I don't get the exception if I don't base64 encoded the images, i.e. leave them intact and can display iframes on the page with the page showing images.
If I take the html after subbing the urls for base64 and run it through toStaticHTML, it removes the src= attribute completely from the tags.
I know the .html with the encoded pngs is right b/c I can open it in Chrome and it displays fine.
My question is I'm trying to figure out why it strips the src= attributes from the tags and how to fix it, for instance, creating the iframe without using jquery and some MS voodoo, or a different technique to sanitize the HTML?
So, a solution I discovered (not 100% convinced it the best and am still looking for something a little less M$ specific) is the MS Webview
http://msdn.microsoft.com/en-us/library/windows/apps/bg182879.aspx#WebView
I use some code like below (where content is the html string with base64 encoded images)
var loadHtmlSuccess = function (content) {
var webview = document.createElement("x-ms-webview");
webview.navigateToString(content);
assetItem.append(webview);
}
I believe you want to use execUnsafeLocalFunction. For example:
var target = document.getElementById('targetDIV');
MSApp.execUnsafeLocalFunction(function () {
target.innerHTML = content}
);

Where to store and how to remove images in a photo gallery?

I'm working on a photo gallery using ASP.NET.
I'm storing user's images in a SQL database. I'm not sure how should displaying images look like.
Let's say there is 1 picture per user, I was doing something like that:
get image from database
save it on server's disc as "file.jpg"
ASP:Image.uri = "file.jpg"
And that worked fine until I found out that If few users loads that page at the very same time, It might not work properly.
Then I though changing "file.jpg" into some random string would help me:
get image from database
save it on server's disc as "ABCDUDHDJSAKFHADGJKHAKADFAD.jpg"
ASP:Image.uri = "ABCDUDHDJSAKFHADGJKHAKADFAD.jpg"
File.Delete("~/ABCDUDHDJSAKFHADGJKHAKADFAD.jpg");
But it wasnt possible to delete this file because it was still being used by a server.
What would be the proper way to solve my problem? User in my photo gallery will eventually see 12 photos at the same time.
What I usually do is serve images from DB using a generic handler (ashx file).
What you need to do is create an ashx file and use something along these lines:
context.Response.BinaryWrite(myImage);
The you create image tags like so:
<img alt="whatever" src="/images.ashx?iid=1243 />
Where iid is the unique ID of the image in the DB.
You should not store the file actually. You should stream it. For example create a handler which returns the image from an user with a specific ID and call it with that ID like image.ashx?id=1. The handler could look like
Image image; // image from your database
using(MemoryStream ms = new MemoryStream())
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.WriteTo(context.Response.OutputStream);
}
Response.ContentType = "image/png";
This handler you can use like a static image file. So, you might even use it for a background-image:
<div style="background-image: url(image.ashx?id=1)">Username</div>

Precompiled views: can I still read the contents at runtime?

I have my views setup to pre-compile, and therefore, at runtime if I were to try and read the view file (e.g. "~\Views\User\Report.cshtml") I'd get the following dummy-text, as opposed to the contents of my view:
This is a marker file generated by the precompilation tool, and should not be deleted!
Problem is, I'd like to re-use the cshtml view, and rerender it another way at runtime, but I cannot due to the above restriction.
The scenario:
An admin can see a list of users in a /User/Report route. It outputs some HTML that has a list of all users, and their information in an HTML table. These admins frequently want to download this html file (styles and all) to email it as an attachment to someone else. They could, of course, go to File->Save in their browser, but I wanted to simplify that action by adding a link to the page "Download this report as HTML" that would simply return the same page's content, as a forced-downloaded HTML file (2012-07-11_UserReport.html).
So, what I tried to do was re-render the view by running the Report.cshtml file's contents through ASP.NET's File() method, like this:
var html = System.IO.File.ReadAllText(Server.MapPath(#"~\Views\User\Report.cshtml"));
var bytes = System.Text.Encoding.UTF8.GetBytes(html);
return File(bytes,"text/html",string.Format("{0}_UserReport.html",DateTime.Now.ToString("yyyy-MM-dd")));
But, like I mentioned earlier, the file comes back as the dummy-text, not the view, since I'm pre-compiling the views.
I understand that to get around the pre-compilition, I could simply copy the Report.cshtml file, and rename it to Report.uncompiled (adding it to the csproj as of course) and read the contents of it, that's an ok solution, but not good enough.
What I would really like to know is: Is there a way I can get at that pre-compiled content? I looked in the Assembly's embedded resources, and they are not there. Any ideas/suggestions?
Updated with current solution
So after searching around some more, and trying to use WebClient/WebRequest to just make a request to the route's URL and send the response back down to the user to download while at the same time trying to pass the user's .ASPXAUTH cookie (that made WebClient/WebRequest time out for some reason? I even tried to create a new ticket, same result) I ended up going with what I didn't want to do: duplicate the view file, and rename it so it's not precompiled.
The view file (Report.uncompiled) had to be modified a bit as it was, and then I ran it through RazorEngine's Razor.Parse method and got what I needed, but it just felt hackey. Would still like a way to access the view file (Report.cshtml) even after it's compiled.
var templateHtml = Razor.Parse(System.IO.File.ReadAllText(Server.MapPath(#"~\Views\User\Report.uncompiled")),model);
var bytes = System.Text.Encoding.UTF8.GetBytes(templateHtml);
return File(bytes, "text/html", string.Format("{0}_UserReport.html", DateTime.Now.ToString("yyyy-MM-dd")));
Would the WebClient class work?
using System.Net;
using (WebClient client = new WebClient ())
{
client.DownloadFile("http://yourwebsite.com/test.html", #"C:\directory.html");
// If you just want access to the html, see below
string html = client.DownloadString("http://yourwebsite.com/test.html");
}
Just have this fire whenever your user clicks a button and then it will save the current content of the page wherever? You could probably also have a directory selector and feed whatever they select into that second parameter.
It essentially does the same thing as the browser save as, if that's what you want.

Dynamically adding CSS cuts down page weight?

Ok, this is bizaare and the only shop I've seen do this..granted we only have 2 developers in this shop. My boss thinks that adding css files individually to pages using a helper method makes our site more efficient because when adding the style references in the Masterpage, then every page gets those styles making the site load slower.
So we have a company.css which is our main styles for stuff that is global like the main buckets such as header, footer, main, etc.
Then he wants me to go into each code-behind of lets say a certain set of pages for one of our features and use a utility method we created to dynamically add the product-related style sheet to those pages. So for instance lets say we have a Reviews & Ratings feature. We put all our reviews & ratings related classes and ids in Reviews.css. Ok great.
So for instance in the .aspx.cs pages Init, we'd put this:
Util.AddStylesheet("Ratings.css");
Now he wants me to include that stylesheet in the codebehind of those pages where our reviews code touches in .aspx pages. But says do not put a reference to Reviews.css in the master page.
Am I the only one who questions this method and says what's the point of having a master page then? I mean really, if you put all your .css references in your master page does the argument of saying that now all pages have all these styles (some not used because they do not relate to that page) add weight to your load time for end users?
I mean common right? Maybe people do this but I've never seen it and it's a management nightmare cause you have references all over the fing place dynamically adding certain .css pages to subsets of .aspx pages.
To me, even though we are an e-commerce site that receives 1 million hits a month, please, I mean seriously adding stylesheets manually and bypassing just putting them all in a master page just boggles my mind. Am I the only one who thinks this is nuts and questions his assumption that doing that would make page weight excessive because they would be inheriting all stylesheets, some which would be wasted .css because it doesn't necessarily relate to that particular page? For me, adding them to the master page is a done deal...simple, maintainable, and who cares.
I can understand page weight with JS, but .css?
What you actually want to do is minimize the number of total http requests made, as well as the total bandwidth used. If you have your reviews.css file linked from the master page, you need an extra http request for every page on your site, whether not you ever use the styles. So in that sense, your boss is right. Don't put this on the master page if it won't be used from all or most of your pages.
That said, I wouldn't have anything in the code-behind for this either, but rather a user control you can put on the required pages to render a style section or link.
I actually do do the compromise fairly often.
Most pages in my sites use all the standard css files declared in the masterpage but there's the odd one page here and there that use a special stylesheet. A high resolution view, a print view or maybe a jquery lighbox/gallery type control.
My ad-hoc stylesheet loading code is as follows:
using System;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
namespace ExtensionMethods
{
public static class PageExtensions
{
public static void AddStyleSheet(this Page page, String Href)
{
PageExtensions.AddStyleSheet(page, Href, "all");
}
public static void AddStyleSheet(this Page page, String Href, String Media)
{
Href = VirtualPathUtility.ToAppRelative(Href);
if (!PageExtensions.StyleSheetAlreadyExists(page, Href))
{
HtmlLink htmlLink = new HtmlLink();
htmlLink.Href = Href;
htmlLink.Attributes.Add("rel", "stylesheet");
htmlLink.Attributes.Add("type", "text/css");
htmlLink.Attributes.Add("media", Media);
page.Header.Controls.Add(htmlLink);
}
}
static private bool StyleSheetAlreadyExists(Page page, String Href)
{
var preExisting = from Control c in page.Header.Controls
where c is HtmlLink && ((HtmlLink)c).Attributes["Href"] == Href
select c;
return preExisting.Any();
}
}
}
Remember, by default CSS files are being CACHED in the browser, so CSS will be loaded only ONCE anyway.
From my experience more seperate CSS files == more duplicated rules == bigger mess.
If you want to save up bit of bandwidth make sure you compress your CSS when writing it, so instead of:
#review
{
margin-top:10px;
margin-left:12px;
margin-bottom:12px;
margin-right:35px;
background-color:#ffffff;
background-image:url(images/blah.png);
background-repeat: repeat-x;
}
You write:
#review{margin:10px 35px 12px 12px;background:#fff url(images/blah.png) no-repeat;}
How about suggesting a compromise?
One master page with the most-commonly used elements defined (headers, links, navigation lists, etc) and then a location-specific stylesheet, ie catalogue.css, for such pages as need those styles. So the css is still able to be cached, but isn't forced on everyone that just visits the about-us page.
It's not ideal, but if the goal is to reduce the bandwidth of a single monolithic css file, it might get you some headway.
As it is, my personal approach is always to use the monolithic stylesheet; though having thought about it I'm tempted to try the suggested approach. It should work? Maybe... =/

Resources