How to use Preprocessor directives in MVC aspx pages - c#

I am using MinifyJS.tt which is a T4 template to minify all my JS files automatically.
In my aspx files, I am referencing all the javascript files.
Now, I want to add a condition (maybe compiler directive) to use the original JS file when I am debugging the application, and to use the minified JS files when I simply run the application without debug.
I tried using #if in the aspx page, but that did not seem to work.
Can we make use of preprocessor directives in aspx pages?
Is there an alternative way to achieve my goal?

You can use the following:
if (!HttpContext.Current.IsDebuggingEnabled)
Script = OptimizeScript(Script);
Further.....there are a couple of comments than discuss the topic further.
From Wilco Bauwer he comments that this property encapsulates the web.config setting and doesn't take the page level debugging into account and if you wanted to....
bool isDebuggingEnabled = Assembly.GetExecutingAssembly().IsDefined(typeof(DebuggableAttribute));
....this is the kiddy to achieve it!!
and Peter Bromberg (C# MVP) offers up another solution using the Global.asax.cs file and a static global application flag being set in the Application_Start event.
public static bool IsDebugMode = false;
protected void Application_Start(object sender, EventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached) IsDebugMode = true;
Taken from Steves blog

Related

Embed Global.asax in assembly

Is it possible to embed the Global.asax file into an assembly? Currently it is represented as a file in the web root directory. But I want to store it as a resource in an assembly.
I'm not sure. Have you tried setting Build Action to Embedded Resource? You can do that by selecting the global.asax file and then the option should appear in your property window.
Ali Reza Dehdar's answer is correct (just change Compile to Embedded Resource in file's properties) and the result can be seen using a decompiler:
Yes you can. You have three options as far as I know:
Use HttpModule but be aware that there are some tricky parts about it. For example the HttpModule Init method might be triggered multiple times (this is based on the number of application instances in the app pool)
Use OWIN
Alternate the HttpApplication type - this one works best for me but I haven't tested it in too many different situations and framework versions. The only thing you need to do in your assembly is paste the following:
.
using System.Web;
using System.Web.UI;
[assembly: PreApplicationStartMethod(typeof(MyAssembly.MyHttpApplication), nameof(MyAssembly.MyHttpApplication.Application_Register)]
namespace MyAssembly
{
public class MyHttpApplication : HttpApplication
{
public static void Application_Register()
{
PageParser.DefaultApplicationBaseType = typeof(MyHttpApplication);
}
protected void Application_Start()
{
// TODO: Your application startup magic :)
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
// TODO:
}
}
}
Trace (or something like that):
System.Web.UI.PageParser.DefaultApplicationBaseType
System.Web.Compilation.BuildManager.GetGlobalAsaxType()
System.Web.HttpApplicationFactory.CompileApplication()
Hope that helps :)

Calling a Function in MasterPage code behind from App_Code .cs file?

I have a file in the App_Code file which is some legacy code, that I use to control Login and sessions. Ideally, once I am logged in, I wish to update the ..Master.cs to fire a function to update the layout (some panels, become enabled etc).
I can access App_Code easily from Code Behind, though I'm unable to figure out how to do this the other way round.
MasterPage.master.cs (code behind)
public static class MasterPage : System.Web.UI.MasterPage{
...
public static void LogInCB{
//stufff
}
...
}
App_Code (something.cs)
public static string(){
//Master.LogInCB(); -tried
//System.Web.UI.MasterPage.LogInCB(); -tried
return something;
}
I'm happy to accept links to official MS documents on things about this.
The code-behind doesn't know what master page you are using. One way to fix this is to cast the Page.Master as your master page class. Once you do that, it will intellisense available functions:
YourNameSpace.MasterPage m = (YourNameSpace.MasterPage)Page.Master;
m.LogInCB();

Dynamically load ASP.NET Page from DLL

I want to create a modular ASP.NET application. Something like, I have a main application that is just some kind of module loader. It only have the one "Default.aspx" page. And, based on the loaded modules, this page will create a menu and links to the pages found in the modules.
I want the modules to be ASP.NET projects packed into dll. So, I want to drop that dll into the "Modules" folder of my main application, it will identify the module, and use reflection to load the modules, inspect them to find the pages, and build a menu from that.
What I've done so far:
In my solution, I have a "DummyModule" project. This project have only 3 pages. Nothing special about it.
And I have another project called "MainApp". Here is the "big deal".
In this project I have a "ModuleLoader" class. When the "LoadModules" method is called, it search for "dll" files in the "Modules" folders of my application. And, using reflection, load these modules. Foreach of these modules, still using reflection, it searches all "Page" types, and stores the names into a list.
On the "Page_Load" method of the "Default.aspx" page, it call de "ModuleLoader" class, gets all modules names and all pages names for each module, and build a menu from that. I created a hyperlink pattern, that have all the information I need to load the right page. That is : "/ModuleName/PageName".
I'm not using the "aspx" extension. OK, so far, so good.
Here is the tricky part.
I've created a HTTPModule called "PageLoaderModule". This modules intercepts all requests, so I can read the URL to identify wich page from wich module I have to load.
And that's exactly what I cannot do and I have no idea how to solve this.
What I'm doing:
public class PageLoaderModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
//clean-up code here.
}
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}
private void context_BeginRequest(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
if (Regex.IsMatch(application.Request.RawUrl, #"/.+/.+"))
{
var parts = application.Request.RawUrl.Split('/').Where(u => !string.IsNullOrWhiteSpace(u)).ToList();
IHttpHandler page = ModuleManager.GetPage(parts[0], parts[1]);
page.ProcessRequest(application.Context);
}
}
#endregion IHttpModule Members
}
The "GetPage" method, find the correct "Page" type in the specified assembly, create an instance and return the that Page instance.
But when I call the "ProcessRequest" method of the IHTTPHandler interface, it doesn't load the page.
It's possible to do that? Any thoughts?
Edit:
I've tried #Slavo suggestion.
While searching for an anwser, I've found and tried a similar solution, implementing my own VirtualPathProvider and VirtualFile.
It almost worked. The virtual path handle and load the correct page but, when the page is loaded, I got the following error in my browser:
Parser Error Message: Could not load type 'DummyModule.Pages.DummyPage3'.
Source Error:
Line 1: <% # Page Language="C#" AutoEventWireup="true" CodeBehind="DummyPage3.aspx.cs" Inherits="DummyModule.Pages.DummyPage3" %>
So, I don't know if I've done something wrong, or this isn't the solution I'm looking for. So, I tried other option.
I correctly marked the "Build Action" of the ".aspx" file as "Embedded Resource", so it can be accessible as a virtual path. But I still got the error above.
This looks like a case where you would want to write a VirtualPathProvider. This class lets you control the logic, which provides components to the compilation system.
When ASP.NET compiles a page to handle the request, by default it only uses the ASPX file and the code-behind. If you write a custom VirtualPathProvider, you will be able to tell it to do otherwise. So whenever ASP.NET needs to compile a page for a particular path to handle the request, your provider can extract it from an assembly.
Here is a helpful article: http://support.microsoft.com/kb/910441
You should handle the PostMapRequestHandler event in your module and set a custom IHttpHandler to the application.Current.Handler property. Here is an example.

ASP.Net - How do I include an embedded JavaScript file from another project?

I've got two projects, one is a control library and another is my main project. From the control library I am currently using a user control and some css files which are embedded in the control library.
I can use the embedded CSS files in my main project by doing the following from my user control's PreRender event:
// Register the default CSS resource
string includeTemplate = "<link rel='stylesheet' text='text/css' href='{0}' />";
string includeLocation = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "MyCompany.ControlLibrary.WebNotify.WebNotify.css");
LiteralControl cssInclude = new LiteralControl(String.Format(includeTemplate, includeLocation));
((System.Web.UI.HtmlControls.HtmlHead)Page.Header).Controls.Add(cssInclude);
I thought it would then make sense to include all my javascript files in a similar fashion, so I included the embedded javascript file doing the following:
// Register the js
string includeTemplate = "<script type='text/javascript' src='{0}'></script>";
string includeLocation = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "MyCompany.ControlLibrary.Scripts.MyScript.js");
LiteralControl jsInclude = new LiteralControl(String.Format(includeTemplate, includeLocation));
((System.Web.UI.HtmlControls.HtmlHead)Page.Header).Controls.Add(jsInclude);
Now, the CSS all works perfectly, however my JS functions throw Object Required exceptions when trying to call them.
Am I going about this the correct way? Or is there a better way of including an embedded js file from another assembly into another project?
Personnally, as others have suggested, use some tools such as FireBug for Firefox, Fiddler, or the Developer Tools for Internet Explorer to check what calls are being made to your servers, and what responses they are sending back - that's what BigBlondeViking's referring to.
I'd also check that you have marked the JS file as "build" in the solution - rather than the default of "take no action".
However, there is indeed a cleaner way of adding embedded script resouces, the ClientScriptManager's "RegisterClientScriptResource" method:
// Get a ClientScriptManager reference from the Page class.
ClientScriptManager cs = Page.ClientScript;
// Register the client resource with the page.
cs.RegisterClientScriptResource(rstype,
"MyCompany.ControlLibrary.Scripts.MyScript.js");
Seems fine; however, at this point I'd really be using client tools to determine whether or not everything's getting there and being used (fiddler/ie toolbar/firebug/etc).
If I had to guess, I would say your code is working, but whatever browser you're using is ignoring the javascript due to the script tag not having a closing tag (i.e. <script></script> opposed to <script />); for some reason some browsers are picky about that

How do you reference .js files located within the View folders from a Page using Asp.net MVC

For example, if I have a page located in Views/Home/Index.aspx and a JavaScript file located in Views/Home/Index.js, how do you reference this on the aspx page?
The example below doesn't work even though the compiler says the path is correct
<script src="Index.js" type="text/javascript"></script>
The exact same issue has been posted here in more detail:
http://forums.asp.net/p/1319380/2619991.aspx
If this is not currently possible, will it be in the future? If not, how is everyone managing their javascript resources for large Asp.net MVC projects? Do you just create a folder structure in the Content folder that mirrors your View folder structure? YUCK!
You can use the VirtualPathUtility.ToAbsolute method like below to convert the app relative url of the .js file to an absolute one that can be written to the page:
<script type="text/javascript" src="<%=VirtualPathUtility.ToAbsolute("~/Views/Home/Index.js") %>"></script>
You should have separated folder structure for scripts. For example JavaScript folder under application root. Storing js files with views is not only affects you with path resolving issues but also affects security and permissions thins. Also it's much more easier later to embed JS files as assembly resources if you will decide to deploy some of your application parts separately in future when they are stored in dedicated subfolder.
For shared javascript resources using the Content folder makes sense. The issue was I was specifically trying to solve was aspx page specific javascript that would never be reused.
I think what I will just have to do is put the aspx page specific javascript right onto the page itself and keep the shared js resources in the Content folder.
Here's a nice extension method for HtmlHelper:
public static class JavaScriptExtensions
{
public static string JavaScript(this HtmlHelper html, string source)
{
TagBuilder tagBuilder = new TagBuilder("script");
tagBuilder.Attributes.Add("type", "text/javascript");
tagBuilder.Attributes.Add("src", VirtualPathUtility.ToAbsolute(source));
return tagBuilder.ToString(TagRenderMode.Normal);
}
}
Use it like this:
<%=Html.JavaScript("~/Content/MicrosoftAjax.js")%>
If you re-route your pages to a custom RouteHandler, you can check for existence of files before handling the RequestContext to the MvcHandler class.
Example (not complete):
public class RouteHandler : IRouteHandler
{
public IHttpHandler
GetHttpHandler(RequestContext requestContext)
{
var request = requestContext.HttpContext.Request;
// Here you should probably make the 'Views' directory appear in the correct place.
var path = request.MapPath(request.Path);
if(File.Exists(path)) {
// This is internal, you probably should make your own version.
return new StaticFileHandler(requestContext);
}
else {
return new MvcHandler(requestContext);
}
}
}

Categories

Resources