I have some data specific to each razor view and and i do not want to hard-code it to each view. So, i want to add view related compile-time data to each view.
Custom attributes do not work for me because we cannot add custom attributes to razor views.
I do not want to re-fetch/populate this data from the data source(dictionary etc.) for each request or when view reached.
So, is there any way to attach data to each view at once throughout the life time of asp.net application?
Note
Actually i want to add scripts/styles generated by webpack for each view statically. Their links include hash values so they change when source scripts/styles change. So, i just want to get them added to each view only once(equivalent to typing them into view) through out the asp.net application, not every time a view loads.
I created a demo application for you here.
You will want to use your appsettings.json file, and inject your settings into your view.
In my appsettings.json I added a section called "ViewConfiguration":
"ViewConfiguration": {
"ExampleKey": "ExampleValue"
}
Your various values will need to go into your ViewConfiguration section.
For example where I have ExampleKey, you will use a generic name like "IndexPageStyleSheet", and where I have ExampleValue, you will need to update each release with the new stylesheet path. This will only need to be updated when the filename changes.
I then created a ViewConfiguration class which stores all of the values from the appsettings.json file.
You will need to create one property per configuration line, and ensure that the name of the property matches the name of the key in your appsettings.json.
For example where my appsettings.json has ExampleKey, my ViewConfiguration class also has an ExampleKey.
public class ViewConfiguration {
public string ExampleKey { get; set; }
}
In your Startup.cs you will need to tell your IOC container to load your configuration values into your configuration object.
In my Startup.cs, my ConfigureServices method loads my "ExampleValue" into ViewConfiguration.ExampleKey automatically.
public void ConfigureServices(IServiceCollection services) {
// This line is the magic that loads the values from appsettings.json into a ViewConfiguration object.
services.Configure<ViewConfiguration>(Configuration.GetSection("ViewConfiguration"));
services.AddMvc();
}
Now, in my _ViewImports.cshtml I inject my ViewConfiguration object so that I don't need to inject it into every single page. This can be anywhere in the _ViewImports.cshtml file. If you only want to inject specific configuration per folder, you can create a new _ViewImports.cshtml file per folder and inject different configuration objects into each one. It's flexible.
#using Microsoft.Extensions.Options;
#* Please rename this variable to something more appropriate to your application: *#
#inject IOptions<ViewConfiguration> InjectedViewConfig
Now, in any page, you can simply reference the property in your ViewConfiguration object.
For example in my Index.cshtml, I reference the ViewConfiguration.ExampleKey property by referencing the strongly typed property on InjectedViewConfig.Value, and it outputs "ExampleValue" on the page.
This value could just as easily be injected into a script or css link tag as the name of a file. It's very flexible.
<h1>Value: #InjectedViewConfig.Value.ExampleKey</h1>
With further research, you will be able to inject these values from any configuration source, such as Azure application settings or Azure Key Vault. Please see this article for more details.
If you are using mvc, you can create models and add it into the views. Since you don't want to recreate for each view, you can create readonly variables.
static readonly MyModel ModelData = new MyModel { PropName = "Hello" };
public IActionResult Index () => View(ModelData);
In your view you can now strongly type the value. If you are looking to use MVVM, you can refer to ViewModel concept still exists in ASP.NET MVC Core?
Implementing IFileProvider and IFileInfo provides changing the contents of view at compile-time. So, we could replace and provide static data in views with a template engine(i.e. http://dotliquidmarkup.org/).
Check this;
https://www.mikesdotnetting.com/article/301/loading-asp-net-core-mvc-views-from-a-database-or-other-location
Related
So SimpleInjector now has a packaging nuget that you can use to isolate different aspects of root composition.
Say I have a configurable composition root in a library that is reused by multiple projects in an application. For example, in an Azure solution I might have a Web role and a Worker role which share a large set of the same dependencies for the most part, but with slightly different configuration options depending on the consumer. When I compose the root, I can pass in a plain old RootCompositionSettings object with properties that tell SimpleInjector how to register dependencies.
However, I am not sure how (or if) I can pass these settings to an IPackage instance. Is it possible to pass custom settings to a SimpleInjector package, and if so, how?
I see that the standard practices for registering packages is to invoke either
container.RegisterPackages(); // scans all loaded assemblies for IPackage
// or
container.RegisterPackages(IEnumerable<Assembly>) // specific assemblies only
...so how can we pass parameters into the packaging instance(s)? Is there some way to do it via the container?
The trick here is to pass the information on with the container to the package. You can do this by using the container's Items dictionary, that is much like ASP.NET's HttpContext.Items collection. This can be done as follows:
using SimpleInjector.Advanced;
container.SetItem(typeof(RootCompositionSettings), settings);
container.RegisterPackages();
Now inside your packages, you can do the following:
var settings =
(RootCompositionSettings)container.GetItem(typeof(RootCompositionSettings));
Please note that:
SetItem and GetItem are extension methods that are located in the SimpleInjector.Advanced namespace. Those methods allow you to access the (internal) Items dictionary.
You can pass in any key you like. Passing in typeof(RootCompositionSettings) is just convenient in this case, but not required.
If you need to call the settings in more places, it might be useful to create a more specific extension method that allows you to access the setting instance, but that's up to you.
Another option is to not use the IPackage interface and the SimpleInjector.Packaging library at all. In most cases it doesn't really add anything and you could simply define a public static method in the assembly that does the same as a package does. For instance:
public static class BusinessLayerBootstrapper
{
public static void Bootstrap(Container container, ScopedLifestyle scopedLifestyle,
RootCompositionSettings settings)
{
// Here the same logic as what you would write in your package.
}
}
Most applications are not that dynamic that you need to load assemblies dynamically and the startup project usually has a hard reference to all the other assemblies. In that case it is perfectly sane to simply call a static method.
And even if you have the requirement of dynamically loading assemblies and allowing them to register their stuff in the container, it's quite trivial to build your own IPackage abstraction instead:\
// Your own IPackage interface
public interface IPackage
{
void RegisterServices(Container container, RootCompositionSettings settings);
}
// Your own extension method
public static void RegisterPackages(this Container container,
RootCompositionSettings settings)
{
var packages =
from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetExportedTypes()
where typeof(IPackage).IsAssignableFrom(type)
where !type.IsAbstract
select (IPackage)Activator.CreateInstance(type);
packages.ToList().ForEach(p => p.RegisterServices(container, settings));
}
In fact, except for some extra validations and filtering out dynamic assemblies, the SimpleInjector.Packaging project is not much more than this.
I am fairly new in MVC4. I'm working with C# Razor view engine using Entity Framework.
I wanted to add new view model that incorporated multiple models (obviously). But I needed a new view. So I created new folder inside Views named "MasterView" with a sample Index.cshtml inside, linked it inside _Layout.cshtml with
<li>#Html.ActionLink("Klick me", "Index", "MasterView")</li>
and when I ran my application, all the default links worked except that one (Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly. ). Am I missing some permission for that page inside some project file? How do I fix it? Thanks in advance.
In MVC you link to Actions inside Controllers rather than pages/views.
In this case you would need a MasterViewController (in the Controllers folder) with an Index action like this:
public ActionResult Index()
{
return View();
}
This will render and return your Index.cshtml file.
In Flex, I want to create some variable that would hold a dictionary of ui components used throughout my application. Ideally, there would be a function in Application component that would return component for id:
public function getComponent4Id(id:String):UIComponent {}
Then I would access component using the following line:
var myComponent:UIComponent = FlexGlobals.topLevelApplication.getComponent4Id("someId");
Now, the only problem is: I want the component returned to be read-only.
It is very convenient to read some properties of myComponent from every corner of application, but I don't want my developers to abuse it and change myComponent.
Is it possible to return a copy of myComponent? Or is it possible to make it read-only somehow?
In the situation you describe, it is not possible to retrieve read only components.
You can create read only variables by implementing get methods without set methods. Something like this:
public var get myValue():UIComponent{
return UIComponent;
}
This would allow you to retrieve the UIComponent instance, myValue, from the component; but you would not be able to set it.
However, this would not prevent people from changing properties on the returned UIComponent unless those properties were also implemented as read only.
I'll add that there is already a method, getChildByName() to retrieve a child component by name. If you have an instance to a parent, you can use this to access the children.
All that said, I'm not sure I completely understand what you hope to achieve; with this functionality.
I'm doing an Windows Phone app where I have a WebApi running in Azure.
I'm using the new "Portable Class Library" (http://msdn.microsoft.com/en-us/library/gg597391.aspx) for my "Models" project which is of cause shared between my WebApi project (this is a normale ASp.NET MVC 4 project) and my Windows Phone project.
This works great and the model (POCO) classes are serialized and deserialized just as I want.
Now I want to start storing some of my Models/POCO objects and would like to use EF Code-first for that, but that's kind of a problem as I can't add the EntityFramework assembly to my "Portable Class Library" project, and really I would not like to either as I only need a small part (the attributes) in my Models project.
So, any suggestions to how a approach this the best way?
UPDATE:
Well, it seems like I can actually add the EntityFramework assembly to the project, but that doesn't really help me, as the attributes I need to use lives in System.ComponentModel.DataAnnotations which can't be used on Windows Phone.
Any suggestions still?
Don't use attributes. Use fluent API instead and create separate assembly for persistence (EF) which will reference your model assembly. Persistence assembly will be use used by your WebAPI layer.
I use a modified approach than Mikkel Hempel's, without the need to use pre processing directives.
Create a standard .NET class library, call it Models
Create a partial class representing what you want to be shared
public partial class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
For non-portable code (like DataAnnotations), create another partial class and use Metadata
[MetadataTypeAttribute(typeof(Person.Metadata))]
public partial class Person
{
internal sealed class Metadata
{
private Metadata() { } // Metadata classes shouldn't be instantiated
// Add metadata attributes to perform validation
[Required]
[StringLength(60)]
public string Name;
}
}
Create a Portable Class Library, and add the class from step 2 "As Link"
When I need my domain-project across multiple platforms, I usually:
Create the standard .NET-class library project for the domain code
For each platform I create a platform specific class library
For each platform specific class library I add the files from the standard .NET-class library as links (Add existing files -> As link) and hence they're updated automatically when you edit either the linked file or the original file.
When I add a new file to the .NET-class library, I add it as links to the platform specific class libraries.
Platform specific attributes (i.e. Table and ForeignKey which is a part of the DataAnnotations-assembly) can be opted out using the pre-processor tags. Lets say I have a .NET-class library with a class and a Silverlight-project with the linked file, then I can include the .NET-specific attributes by doing:
#if !SILVERLIGHT
[Table("MyEntityFrameworkTable")]
#endif
public class MyCrossPlatformClass
{
// Blah blah blah
}
and only include the DataAnnotations-assembly in the .NET-class library.
I know it's more work than using the Portable Class Library, but you can't opt out attributes in a PCL like in the example above, since you're only allowed to reference shared assemblies (which again DataAnnotations is not).
I am looking for some help with designing some functionality in my application. I already have something similar designed but this problem is a little different.
Background:
In my application we have different Modules. Data in each module can be associated to other modules. Each Module is represented by an Object in our application.
Module 1 can be associated with Module 2 and Module 3. Currently I use a factory to provide the proper DAO for getting and saving this data.
It looks something like this:
class Module1Factory {
public static Module1BridgeDAO createModule1BridgeDAO(int moduleid) {
switch (moduleId)
{
case Module.Module2Id: return new Module1_Module2DAO();
case Module.Module3Id: return new Module1_Module3DAO();
default: return null;
}
}
}
Module1_Module2 and Module1_Module3 implement the same BridgeModule interface. In the database I have a Table for every module (Module1, Module2, Module3). I also have a bridge table for each module (they are many to many) Module1_Module2, Module1_Module3 etc.
The DAO basically handles all code needed to manage the association and retrieve its own instance data for the calling module. Now when we add new modules that associate with Module1 we simply implement the ModuleBridge interface and provide the common functionality.
New Development
We are adding a new module that will have the ability to be associated with other Modules as well as specific properties of that module. The module is basically providing the user the ability to add their custom forms to our other modules. That way they can collect additional information along with what we provide.
I want to start associating my Form module with other modules and their properties. Ie if Module1 has a property Category, I want to associate an instance From data with that property.
There are many Forms. If a users creates an instance of Module2, they may always want to also have certain form(s) attached to that Module2 instance. If they create an instance of Module2 and select Category 1, then I may want additional Form(s) created.
I prototyped something like this:
Form
FormLayout (contains the labels and gui controls)
FormModule (associates a form with all instances of a module)
Form Instance (create an instance of a form to be filled out)
As I thought about it I was thinking about making a new FormModule table/class/dao for each Module and Property that I add. So I might have:
FormModule1
FormModule1Property1
FormModule1Property2
FormModule1Property3
FormModule1Property4
FormModule2
FormModule3
FormModule3Property1
Then as I did previously, I would use a factory to get the proper DAO for dealing with all of these. I would hand it an array of ids representing different modules and properties and it would return all of the DAOs that I need to call getForms(). Which in turn would return all of the forms for that particular bridge.
Some points
This will be for a new module so I dont need to expand on the factory code I provided. I just wanted to show an example of what I have done in the past.
The new module can be associated with: Other Modules (ie globally for any instance of that module data), Other module properties (ie only if the Module instance has a certian value in one of its properties)
I want to make it easy for developers to add associations with other modules and properties easily
Can any one suggest any design patterns or strategy's for achieving this?
If anything is unclear please let me know.
Thank you,
Al
You can use springs Dependency Injection feature. This would help you achieve the flexibility of instantiating the objects using an xml configuration file.
So, my suggestion would be go with the Springs.