How render each bundled file separate in debug mode?
I want to have rendered css and js file separate in my view, because it is hard to debug javascript files when all files are bundled.
You need to create simple BundleHelper class.
After that in your *.cshtml file yo can use
#BundleHelper.RenderScripts("~/bundles/js")
#BundleHelper.RenderStyles("~/bundles/style")
public class BundleHelper
{
private static IEnumerable<string> GetOriginalFilePaths(string bundlePath)
{
var resolver = new BundleResolver(BundleTable.Bundles);
IEnumerable<string> scriptPaths = resolver.GetBundleContents(bundlePath).ToList();
return scriptPaths;
}
public static IHtmlString RenderScripts(string bundlePath )
{
if (BundleTable.EnableOptimizations) return Scripts.Render(bundlePath);
var scriptPaths = GetOriginalFilePaths(bundlePath);
return Scripts.Render(scriptPaths.ToArray());
}
public static IHtmlString RenderStyles(string bundlePath)
{
if (BundleTable.EnableOptimizations) return Styles.Render(bundlePath);
var stylePaths = GetOriginalFilePaths(bundlePath);
return Styles.Render(stylePaths.ToArray());
}
}
In production it will work as you want and in development will work like as you haven't used bundling.
Related
I am trying to create a simple GET API endpoint which will return the JSON of the current environment appsettings.json file, for example for the development environment it will return the contents of appsettings.Development.json file and for production environment it will return the contents of appsettings.Production.json file.
I don't know a nice way to dump the entire config file. What I know though is ways to read single config values through the injected config["Key"] or read a section through
config.GetSection("SectionName").Get<MyCustomSectionClass>()
approach. These options are not feasible as the file is big and the content may change.
This is an ASP.NET Core 6 Core Web API application, created through the default Visual Studio template.
If you want to return entire appsettings.xxx.json file, You can try this simple demo. I not sure if there is a better method, But this method works well in my project.
using Newtonsoft.Json;
private readonly IWebHostEnvironment _env;
public WeatherForecastController(IWebHostEnvironment env)
{
_env = env;
}
[HttpGet]
public IActionResult Get()
{
if (_env.IsDevelopment())
{
var path = Path.Combine(_env.ContentRootPath, "appsettings.Development.json");
string json = System.IO.File.ReadAllText(path);
object jsonObject = JsonConvert.DeserializeObject(json);
return Ok(jsonObject);
}else if (_env.IsProduction())
{
//read from appsettings.Production.json
return Ok();
}
else
{
//..........
return Ok();
}
}
We have an MVC application that is deployed as 3 different versions in production (seperate business areas demand seperate DBs and UIs). The only problem is that a few users use more than 1 of these applications and because they look vsually similar people get confused as to which one they are using.
I use web.config transforms to change the app title but what would like to do is deliver each one with a different css file. Is there a way to:
Use transforms on publish to edit an existing css file?
or
Swap the css file for another on publish?
Any help pointing me in the right direction would be great.
Thanks
What I did in a similar case : I dynamicly put a class on the body <body class="theme-site#AppSettingParam"> and i have only one CSS with override like :
.theme-site1 { background-color:blue; }
.theme-site2 { background-color:red; }
if a user uses multiple sites, it does not re-download the css and i have only one css to maintain.
This isn't the answer you're looking for right now, but if you do reconsider using the same site with different configurations, take a look at what I did recently to dynamically change CSS etc:
I decided that each 'version' of the website would use a unique reference in the query string. Based on this, I'll find the correct content, load the paths into a Model and send it to the view.
Here's the controller:
public ActionResult Index()
{
List<string> listOfAcceptableRef = new List<string>() { "uniqueCode1", "uniqueCode2" };
string uniqueRef=null;
if (Request.QueryString["ref"]!=null)
policyRef = Request.QueryString["ref"].ToLower();
if (string.IsNullOrWhiteSpace(uniqueRef) || (!string.IsNullOrWhiteSpace(uniqueRef) && !listOfAcceptableRef.Contains(uniqueRef)))
{
throw new Exception("This reference key is unknown.");
//return RedirectToAction("KeyError");
}
return View(GetPageContext(uniqueRef));
}
Grab the reference code from the query string and then generate a model containing the relevant CSS paths from a context factory.
Here's my model:
public class PageContext
{
public string Ref { get; set; }
public string TabId { get; set; }
public string TabName { get; set; }
public string SiteTitle { get; set; }
public string CssPath { get; set; }
public PageContext()
{
Products = new List<ProductInfo>();
}
}
And my context factory:
public class ContextFactory<T>
{
private ContextFactory()
{
}
static readonly Dictionary<string, Type> _dict = new Dictionary<string, Type>()
{
{ "uniqueRef1", Type.GetType("The.Full.Page.Namespace.UniqueSite1Context")},
{ "uniqueRef2", Type.GetType("The.Full.Page.Namespace.UniqueSite2Context")}
};
public static bool Create(string reference, out T context)
{
context = default(T);
Type type = null;
if (_dict.TryGetValue(reference, out type))
{
context = (T)Activator.CreateInstance(type);
return true;
}
return false;
}
}
And the actual context instance with the CSS paths etc:
public class UniqueSite1Context : PageContext
{
public UniqueSite1Context()
{
this.Ref = "uniqueSite1";
this.CssPath = "Content/UniqueSite1Context.css";
this.DisclaimerPath = "Content/UniqueSite1Context.pdf";
this.SiteTitle = "UniqueSite1";
}
}
After all that, just render the CSS using the model's paths:
#section Styles {
#{
string path = Url.Content("~") + Model.CssPath;
<link href="#path" rel="stylesheet" type="text/css" />
}
}
Architecturally speaking, you could extend this (or rather the concept of it) to use different logic and data contexts based on which 'site' the user goes to.
Have you considered transform files? They change the settings in your web.config file when you publish, based on the publish profile selected. Typically the profiles available by default is "Debug" and "Release", but you could add more like "Site1" and "Site2" with different CSS paths.
Take a look at how they work here. (I haven't used them myself so I can't help much in the way of code examples).
I searched a lot and still couldn't find a solid solution for this. Suppose you have methods in your application. This methods use "System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration" to access some setting in the web.config. If you try to test these methods, your tests will fail because your test project doesn't have web.config.
What is the best way to solve this problem. For projects with simple config file, I usually use a method like this as facade method.
public class Config
{
public static String getKeyValue(String keyName)
{
if (keyName == String.Empty) return String.Empty;
String result = "";
System.Configuration.Configuration rootWebConfig1 =
System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);
if (rootWebConfig1.AppSettings.Settings.Count > 0)
{
System.Configuration.KeyValueConfigurationElement reportEngineKey =
rootWebConfig1.AppSettings.Settings[keyName];
if (reportEngineKey != null)
{
result = reportEngineKey.Value;
}
}
return result;
}
}
Every time I tried to set the path for OpenWebConfiguration( ), I got the error "The relative virtual path is not allowed"
To make that scenario more testable, I usually take the approach of making a "settings manager" of my own, and giving it an interface. So for example:
public interface IConfig
{
string GetSettingValue(string settingName);
}
Then I can have my "real" implementation:
public sealed class Config : IConfig
{
public string GetSettingValue(string settingName)
{
// your code from your getKeyValue() method would go here
}
}
Then my code that uses it would take in an instance of this (this is an example of the Dependency Inversion Principal):
public void DoStuff(IConfig configuration)
{
string someSetting = configuration.GetSettingValue("ThatThingINeed");
// use setting...
}
So now for my production code, I can call DoStuff and pass in an instance of Config.
When I need to test, I can use a mocking tool (Moq, JustMock, RhinoMocks, etc) to create a fake IConfig that returns a known value without hitting the actual .config file, or you can do it without a mocking framework by making your own mocks (and store them in your test project).
public class ConfigMock : IConfig
{
private Dictionary<string, string> settings;
public void SetSettingValue(string settingName, string value)
{
settings[settingName] = value;
}
public string GetSettingValue(string settingName)
{
return settings[settingName];
}
}
and
[Test]
public void SomeExampleTest()
{
var config = new ConfigMock();
config.SetSettingValue("MySetting", "SomeValue");
var underTest = new MyClass();
underTest.DoStuff(config);
}
The easiest way to do this is to use a mocking library such as moq. It takes a bit of time to figure it out, but once you do you can abstract away most of your plumbing to return the values you need for repeatable, consistent testing.
I use ModuleManager load a module, like this Class:
public class LoadModule
{
private static var info:IModuleInfo;
private static var display:IVisualElement;
private static var downloadBar:ProgressBar;
private static var parent:Group;
public function LoadModule()
{
}
//load module
public static function load(url:String, parent:Group, bar:Boolean = true):void {
LoadModule.parent = parent;
info = ModuleManager.getModule(url);
info.addEventListener(ModuleEvent.READY, readyHandler);
info.addEventListener(ModuleEvent.SETUP, setupHandler);
info.addEventListener(ModuleEvent.ERROR, errorHandler);
info.load(null, null, null, parent.moduleFactory);
}
//add display object
private static function readyHandler(event:ModuleEvent):void {
LoadModule.display = event.currentTarget.factory.create() as IVisualElement;
parent.addElement(LoadModule.display);
}
private static function setupHandler(event:ModuleEvent):void {
}
//unload module
public static function unload():void {
if (LoadModule.info != null) {
LoadModule.info.addEventListener(ModuleEvent.UNLOAD, unloadHandler);
LoadModule.info.unload();
if (parent.getElementIndex(LoadModule.display) != -1) {
parent.removeAllElements();
LoadModule.display = null;
}
}
}
private static function unloadHandler(event:ModuleEvent):void {
LoadModule.info.removeEventListener(ModuleEvent.UNLOAD,unloadHandler);
trace("unloadModue");
}
//
private static function progresshandler(event:ModuleEvent):void {
downloadBar.label = "haved" + Math.round((event.bytesLoaded /event.bytesTotal) * 100) + "%";
}
private static function errorHandler(event:ModuleEvent):void {
throw Error(event.errorText);
}
public static function setDownloadbar(downloadBar:ProgressBar):void {
LoadModule.downloadBar = downloadBar;
}
}
Then i load a module and unload a module:
LoadModule.unload(); // 1
LodModule.load('..one.swf', parent);
LoadModule.unload(); //2
LodModule.load('...one.swf', parent);
In theory, It's only one module in my application, and I use "PopUpManager" pop a box, it shoud be one box. But, in fact, It's pop tow box.
I use Flash builder debug this code, and It does not notice me unloade swf..
I guess, It has tow module in appliction.
So, I need help. How to unload module in ModuleManager. I wish one module in application , not tow.
Thanks.
If I understand the question correctly, it sounds like you are having trouble unloading your module. There's a great Adobe resource that can help you solve these issues. A few considerations:
"If you have a module that does not unload, the steps to diagnose the problem are:
1) Make sure the module is being loaded into a child applicationDomain (use default parameters for the load() method in most cases)
2) Use the profiler to make sure there are no references to objects in the module."
If you reference any objects in the module, the module will not unload. You will want to check that the following areas make no reference to the module in question:
Styles
Resources
ExternalInterface.addCallback functions
Timers and Timer mechanisms
Listeners
Focus
Remote Objects
Loaded images
I'm currently developing a site using ASP.Net MVC3 with Razor. Inside the "View/Shared" folder, I want to add a subfolder called "Partials" where I can place all of my partial views (for the sake of organizing the site better.
I can do this without a problem as long as I always reference the "Partials" folder when calling the views (using Razor):
#Html.Partial("Partials/{ViewName}")
My question is if there is a way to add the "Partials" folder to the list that .Net goes through when searching for a view, this way I can call my view without having to reference the "Partials" folder, like so:
#Html.Partial("{ViewName}")
Thanks for the help!
Solved this. To add the "Shared/Partials" sub directory I created to the list of locations searched when trying to locate a Partial View in Razor using:
#Html.Partial("{NameOfView}")
First create a view engine with RazorViewEngine as its base class and add your view locations as follows. Again, I wanted to store all of my partial views in a "Partials" subdirectory that I created within the default "Views/Shared" directory created by MVC.
public class RDDBViewEngine : RazorViewEngine
{
private static readonly string[] NewPartialViewFormats =
{
"~/Views/{1}/Partials/{0}.cshtml",
"~/Views/Shared/Partials/{0}.cshtml"
};
public RDDBViewEngine()
{
base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(NewPartialViewFormats).ToArray();
}
}
Note that {1} in the location format is the Controller name and {0} is the name of the view.
Then add that view engine to the MVC ViewEngines.Engines Collection in the Application_Start() method in your global.asax:
ViewEngines.Engines.Add(new RDDBViewEngine());
Thank you for your answers. This has organized my Shared folder, but why do you create a new type of view engine? I just made a new RazorViewEngine, set it's PartialViewLocationFormats and added it to the list of ViewEngines.
ViewEngines.Engines.Add(new RazorViewEngine
{
PartialViewLocationFormats = new string[]
{
"~/Views/{1}/Partials/{0}.cshtml",
"~/Views/Shared/Partials/{0}.cshtml"
}
});
It´s nice to custom the view engine, but if you just want to have a subfolder por partials you don´t need that much...
Just use the full path to the partial view, as done for the Layout View:
#Html.Partial("/Views/Shared/Partial/myPartial.cshtml")
Hope it helps someone...
If you are doing this in ASP.NET Core, simple go to the Startup class, under ConfigureServices method, and put
services.AddMvc()
.AddRazorOptions(opt => {
opt.ViewLocationFormats.Add("/Views/{1}/Partials/{0}.cshtml");
opt.ViewLocationFormats.Add("/Views/Shared/Partials/{0}.cshtml");
});
I've updated lamarant's excellent answer to include Areas:
public class RDDBViewEngine : RazorViewEngine
{
private static readonly string[] NewPartialViewFormats =
{
"~/Views/{1}/Partials/{0}.cshtml",
"~/Views/Shared/Partials/{0}.cshtml"
};
private static List<string> AreaRegistrations;
public RDDBViewEngine()
{
AreaRegistrations = new List<string>();
BuildAreaRegistrations();
base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(NewPartialViewFormats).ToArray();
base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(areaRegistrations).ToArray();
}
private static void BuildAreaRegistrations()
{
string[] areaNames = RouteTable.Routes.OfType<Route>()
.Where(d => d.DataTokens != null && d.DataTokens.ContainsKey("area"))
.Select(r => r.DataTokens["area"].ToString()).ToArray();
foreach (string areaName in areaNames)
{
AreaRegistrations.Add("~/Areas/" + areaName + "/Views/Shared/Partials/{0}.cshtml");
AreaRegistrations.Add("~/Areas/" + areaName + "/Views/{1}/Partials/{0}.cshtml");
}
}
}
Then don't forget to include in your application start:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
ViewEngines.Engines.Add(new RDDBViewEngine());
}
}
You can also update the partialview-location-formats of the registered RazorViewEngine.
Place the below code in Application_Start in Global.asax.
RazorViewEngine razorEngine = ViewEngines.Engines.OfType<RazorViewEngine>().FirstOrDefault();
if (razorEngine != null)
{
string[] newPartialViewFormats = new[] {
"~/Views/{1}/Partials/{0}.cshtml",
"~/Views/Shared/Partials/{0}.cshtml"
};
razorEngine.PartialViewLocationFormats =
razorEngine.PartialViewLocationFormats.Union(newPartialViewFormats).ToArray();
}
You can create register your own view engine that derives from whatever view engine your are using (Webforms/Razor) and specify whatever locations you want in the constructor or just add them to the list of already existing locations:
this.PartialViewLocationFormats = viewLocations;
Then in application start you would add your view engine like so:
ViewEngines.Engines.Add(new MyViewEngineWithPartialPath());