Set razor view path to a external folder - asp.net

Currently we use plugins with razorgenerator. This works ok, but when the view needs to be editted it needs to be compiled every time. This makes us less productive then wanted. I was working on a custom razor viewengine to solve this. To get it working I need to set the view for the area's to a local directory.
I tried
public class PluginRazorViewEngine : RazorViewEngine
{
public PluginRazorViewEngine()
{
var x = this.AreaViewLocationFormats.ToList();
x.Insert(0, "C:/XXXXX/Areas/Module/Views/{1}/{0}.cshtml");
this.AreaViewLocationFormats = x.ToArray();
}
}
Though this gives the error:
The relative virtual path 'C:/XXXXX/Areas/Module/Views/Items/Index.cshtml' is not allowed here.
Is it possible to set the viewpath outside of the project?

I could not find exactly where that error is thrown but I believe you cannot set a path outside of the application the way you are trying to. The RazorViewEngine inherits from BuildManagerViewEngine which in turn inherits from VirtualPathProviderViewEngine. The VirtualPathProviderViewEngine uses the VirtualPathProvider of the host environment.
Thus, it seems you cannot use a direct path and are required to pass in a Virtual path or you could rewrite the underlying layers yourself by directly inheriting from IViewEngine which is what VirtualPathProviderViewEngine inherits from (see image below).
I might be mistaken but I also believe this is enforcing the same principle as specified here that you cannot deliver content from outside the site path.
Have you tried using a relative path to see if that gets mapped correctly. A relative path dependent on the application's root?
Looking through the source of VirtualPathProviderViewEngine you will also notice that the FileExists method of the VirtualPathProvider class is used extensively to find the requested razor file.
Source of inheritance diagram: http://theshravan.net/blog/configure-the-views-search-locations-in-asp-net-mvc/

Related

Silverstripe: Frontend form with file upload could overwrite existing files

I'm running into a small problem with a project of mine. I have a working frontend form that can be used to put an image into a dataobject and save it. No problem so far, but it's an avatar so when one of my users uploads avatar.png it could be overwritten by another user using the same filename. This is expected Silverstripe behavior, but in my case unwanted.
Is it possible to prepend a string to the image name, for example, the username (which is unique)? In a perfect world that would only happen on the front end of course, but I will settle for less :-)
Regards,
Joost.
Well, in the end I found the following solution. The upload class has a setting, that lets you specify if the image will be replaced or if the image filename will be changed, and uploaded nonetheless. The funny part is that the default is set to not replace.
The formfield class that I am using is UploadField, which extends FileField, that uses the upload class. By default, the UploadField class sets the upload to replace the old file, using Upload->setReplaceFile(true).
I therefore decided to create a new upload class, and replace the old one with that:
class VBUpload extends Upload {
public function setReplaceFile($bool) {
if(strpos($_SERVER["REQUEST_URI"],'admin/')===false) {
$this->replaceFile = false;
} else {
$this->replaceFile = $bool;
}
}
}
I only want the default working changed when called from the front end, and maybe there's a cleaner way to achieve that. But this one is working for me.
The only thing to do next is forcing the system to actually using the class, so I added this to the /mysite/_config/config.yml:
Injector:
Upload:
class: VBUpload
This probably can also be done with a normal extension, but I'll change that when the need arises :-)

How to deal with Web Controls in a class library which have file dependancies

I could do with a little guidance if possible..
I'm building a class library to contain custom web controls. I've transformed many of the jQuery UI elements into .NET classes for dynamic use in pages. e.g.
Dim Msg As New Dialog("Dialog Title", New LiteralControl("Dialog Content"))
Msg.Width.Value = 500
Msg.Height.Value = 300
Me.Controls.Add(Msg )
The necessary scripts get inserted into the head during CreateChildControls, and any jQuery file references are added to the head e.g.
RegisterScriptFile("~/Scripts/jquery-1.5.1.js")
RegisterScriptFile("~/Scripts/UI/jquery.ui.core.js")
RegisterScriptFile("~/Scripts/UI/jquery.ui.widget.js")
RegisterScriptFile("~/Scripts/UI/jquery.ui.mouse.js")
RegisterScriptFile("~/Scripts/UI/jquery.ui.draggable.js")
RegisterScriptFile("~/Scripts/UI/jquery.ui.position.js")
RegisterScriptFile("~/Scripts/UI/jquery.ui.resizable.js")
RegisterScriptFile("~/Scripts/UI/jquery.ui.dialog.js")
The WebControl base class handles inserting the references into the Page Head.
This is brilliant, however there's a problem...the file paths may differ between applications which consume the control library.
My choices that I can see are:
A) Embed the files as resources within the library itself....however the CSS styling would be non-customisable between the individual aplications, and any changes to CSS/JS would need a re-compile.
B) Define and use a standardised file heirarchy. Each application needing a folder call 'Scripts' with a fixed file heirarchy within, so the control knows where to reference the required files. The problem I can see here is that it might not always be possible to use this standardised heirarchy and could make using the library cumbersome.
C) Create a property for each control, for each file it requires. Again this would become cumbersome and a pain to use, because each instantiated control would have to have those properties set.
D) Make some kind of ResourceUrlLibrary Dictionary like class which the consuming app can populate, then give to each control as it's instantiated. However, this seems convoluted and could cause confusion for other developers.
If anyone has come across this problem and could spare me some guidance that would be brilliant :)
If its a custom control, it has a reference to the Page class, which then has a method call ResolveClientUrl to generate a relative URL for you. So that can take care of that scenario. You may want to expose a ScriptsFolder property that allows you to store the path to the scripts rather than hard-coding it too.
If this is for your own custom project, standardizing on a folder is fine, but if you are creating a common library to be reused, requiring a specific folder isn't a good idea, and you can then use the ScriptsFolder property to remedy this, or store the folder path in the config. It's OK to standardize on the use of an application setting.
To confirm, I use Telerik controls, and they go the route of having a property that defines a custom path to the script (since they rely on one for a specific control), and they also have certain settings that can be overridden by adding an application setting.
HTH.

Why the difference in how Inherits works in the WebForm?

I stumbled on something that surprised me. I'm migrating a couple of WebForms from a common web project into two different web projects. The projects are treating the Inherits tag (in the source / HTML view) differently.
Take this example: SomeWonderfulPage.aspx / SomeWonderfulPage.aspx.cs
The code-behind is totally standard (and no namespace):
public partial class SomeWonderfulPage : System.Web.UI.Page
{
//...
}
In one project Inherits="SomeWonderfulPage" works and Inherits="MyNameSpace.Blah.SomeWonderfulPage" fails (intellisense can't see the Label controls, and the project won't build); and in the other project it's the other way around.
I confirmed the behavior by making new WebForms in both projects via the 'Add New Item...' command in VS2008 - same results.
Does anyone know why this is?
When I copied the web pages from the first site (into which I had refactored the webforms) into the second site the SomeWonderfulPage.designer.cs files came across but weren't included in the project by default.
In such cases I found (on further exploration) that I couldn't get either Inherit to work.
Including the designer files fixed it. Doh.

Visual Studio and ASP.Net Path question

Question about paths while working in Visual Studio. In my master page I have some paths to load css files as well as javascript files.
My first question is if I use relative paths, should the relative path be from the location of the master page file? For example if I keep all my master page files in a folder off the site root called MasterPages should I assume that is the starting point for my relative paths to load the css files? If that master page is used to wrap an aspx file several directories down the tree is the hard coded relative path still valid?
Second question, is there a way to use absolute paths so that everything works on my local machine as well as when I move the files up to the webroot? For example my app path on my local machine may be localhost/myappdir/default.aspx but when i move the app to the server there is no myappdir and the default.aspx is in the webroot. I do not want to have to change paths in the files after they are moved up to the server.
currently I have..
src="<%= VirtualPathUtility.ToAbsolute("~/lib/css/style.css")%>"
but this way Visual Studio cannot find the css file to update intellisence
If you use relative paths to your css/Javascript files, then they will need to be relative to the page, not the Master page.
This article does a very nice job of explaining the options you have in this situation, and towards the end they propose a nice solution to this type of problem, a user control that renders the script or link tag for you and calls ResolveClientUrl to make the paths correct.
As a rule, you should be using server-relative paths (as in, /images/stuff.gif) to everything all the time. Using relative paths (as in ../images/stuff.gif) will screw you every single time, as will trying to rely on ASP.NET "Magic" such as VirtualPathUtility.ToAbsolute and ResolveClientUrl.
Occasionally, on the server you'll need to prepend that path with a tilda (as in ~/images/stuff.gif) so that it will correctly navigate the virtual directories that ASP.NET requires you to base all your projects in.
Naturally, this also means that you'll need to set your dev box up with multisite so that you can change your root to something like http://mysite.dev/ and ensure that all your server-relative paths work correctly. (Using the VS.NET built-in server would technically work around that too, but really, do you want to use that thing???)
Use the "~" operator to resolve everything relative to the root. Never use relative paths. Even when I'm not using themes, I use their syntax to get simple syntactic access to my CSS files by creating a folder structure like : App_Themes/Style/stylesheet.css Then in my ASPX page directives I add Theme="Style" and my CSS files will be automatically resolved - not exactly conventional but very effective :-)
UPDATE:
To resolve the JS, you could use the following in your master page code-behind:
string myScript = "js/footerFix.js";
Page.ClientScript.RegisterClientScriptInclude("myKey", myScript);
With IIS7 you do not need to change anything to get "multi-site" behaviour; this is baked in. For example you can have several sites as follows and reach them via URL without any separate configuration aside from creating the virtual directories:
localhost/project1
localhost/project2
localhost/project3
Put your script and stylesheet links in a <head Id="headRegion" runat="server" /> in the master page. Their src/href should be the absolute URL path that you get when running in WebDev.WebServer (eg /ProjectWeb).
In the Master Page OnPreRenderComplete(), rewrite any URLs inside headRegion.
Visual Studio can intellisense your scripts and css, and the project can be deployed under any virtual path.
protected override void OnPreRenderComplete( EventArgs e )
{
base.OnPreRenderComplete( e );
var root = Request.ApplicationPath;
if (root == "/") {
root = "";
}
foreach (Control c in headRegion.Controls) {
if (c is HtmlLink) {
HtmlLink hlink = c as HtmlLink;
hlink.Href = ReplacePath( hlink.Href, root );
} else if (c is LiteralControl) {
var literal = c as LiteralControl;
literal.Text = ReplacePath( literal.Text, root );
}
}
}
string ReplacePath( string content, string prefix )
{
return content.Replace("/ProjectWeb", prefix );
}

Loading Flex resources relative to server root as opposed to .swf location

I have a large (700kb) Flex .swf file representing the main file of a site.
For performance testing I wanted to try and move it off to Amazon S3 hosting (which i have already done with certain videos and large files).
I went ahead and did that, and updated the html page to reference the remote .swf.
It turns out that Flash will load any resources relative to the .swf file accessing the resource - no matter what the root of the html page is. So my resources are now being loaded from the remote site (where they don't exist).
There are two obvious things I could do :
* copy all my resources remotely (not ready for this since i'm just testing now)
* add in some layer of abstraction to every URL that the .swf accesses to derive a new path.
I really want to flick a switch and say 'load everything relative to [original server]'.
Does such a thing exist or am I stuck loading everythin from the remote machine unless I fully qualify every path?
i want to avoid anything 'hacky' like : subclass Image and hack the path there
Append a slash before your urls, this should load relative to the domain instead of the current folder:
foo.load('/like/this/image.jpg')
This is a bit quick and dirty, feeding a "relative" url via a querystring (or the base parameter) would be way more flexible.
You could try specifying the base parameter of your SWF's embed/object tags. In theory it defines the base path that will be used to resolve relative paths for loading, but I don't know if it will work if the base value points to a different server from where the SWF is.
See the docs on embed/object params here. Scroll down to "base" at the middle.
If that doesn't work, another thing I've seen people do is to pass in a custom base path via flashvars. Then inside your SWF, you check if that base path is defined, and if so prepend it to relative URLs before loading.

Resources