I am developing an event management application with ASP.NET Boilerplate and Module Zero.
The features management included with ASP.NET Boilerplate allows to scope features to an Edition or to a Tenant.
I would like to know if it's possible to extend features to be scoped to events, so I can assign specific features of our application individually to each event our tenants create.
Is this possible? What is the best way to implement this with ABP?
I would like to know if it's possible to extend features to be scoped to events... Is this possible?
Sure. You can:
subclass Feature
subclass FeatureSetting
create a new FeatureScopes enum to include Events
implement and replace IFeatureChecker
implement and replace IFeatureManager
override methods in FeatureValueStore
That looks like a lot of work. But it is done like that for maintainability and separation of concerns.
What is the best way to implement this with ABP?
You're better off using Feature as-is, enabled for the tenant, and then replace FeatureChecker:
public async Task<string> GetValueAsync(int tenantId, string name)
{
var feature = _featureManager.Get(name);
var value = await FeatureValueStore.GetValueOrNullAsync(tenantId, feature);
if (value == null)
{
return feature.DefaultValue;
}
// Check if Feature is enabled for Event
// ...
return value;
}
Related
28.2 ForAllMaps, ForAllPropertyMaps, Advanced and other “missing” APIs
Some APIs were hidden for normal usage. To light them up, you
need to add an using for AutoMapper. Internal and call the Internal
extension method on the configuration object. Most users don’t need
these advanced methods. Some expose internals and are not subject to
the usual semantic versioning rules. To avoid such tight coupling to
AutoMapper, you should try to stick to the public API.
I have ForAllMapps call in the project (NopCommerce 4.50.1). The original project uses AutoMapper 8.1.1. I want to update it to the newest package (11). What can I use instead (with example if possible).
Thank you.
For AutoMap 11, Some APIs were hidden for normal usage. To light them up, you need to add an using for AutoMapper.Internal and call the Internal extension method on the configuration object. Most users don’t need these advanced methods. Some expose internals and are not subject to the usual semantic versioning rules. To avoid such tight coupling to AutoMapper, you should try to stick to the public API.
ForAllMaps, ForAllPropertyMaps, Advanced and other “missing” APIs, use the API instead:
void ConfigurationExpression(IMapperConfigurationExpression cfg)
{
AutoMapper.Internal.InternalApi.Internal(cfg).ForAllMaps(MappingExpression);
}
https://docs.automapper.org/en/latest/11.0-Upgrade-Guide.html#forallmaps-forallpropertymaps-advanced-and-other-missing-apis
https://github.com/AutoMapper/AutoMapper/blob/9f2f16067ab201a5a8b9bc982f3a37e8790da7a0/src/AutoMapper/Internal/InternalApi.cs#L15
If they consider ForAllMaps to be too tightly coupled, you could write your own implementation:
public class AutoMapperConfig : Profile
{
public AutoMapperConfig()
{
this.CreateCustomMap<Model1, Model2>()
}
}
public static class ProfileExtensions
{
public static IMappingExpression<TFrom, TTo> CreateCustomMap<TFrom, TTo>(this Profile profile)
{
var mappingExpression = profile.CreateMap<TFrom, TTo>();
// do something like mappingExpression.ForMember(...)
return mappingExpression;
}
}
I just want to authorize to users for my action like
[Authorize(Users = "anupam,ashwin")]
public ActionResult AddArticle()
{
return View();
}
Reference Here
But I only found Roles in AuthorizeAttribute as shown below
I want to use Users attribute for Authorize, is there any alternative way in asp.net core ??
The article you're referencing is for ASP.NET MVC, not ASP.NET Core. In general, you should ignore anything there, as it's no longer applicable.
It would seem ASP.NET Core removed support for specifying Users in AuthorizeAttribute (though, frankly, I was unaware that ASP.NET MVC had it in the first place). It's possible to mimic this functionality via policies, though:
services.AddPolicy("MustBeJoeOrBob", p =>
p.RequireAssertion(c =>
new[] { "Joe", "Bob" }.Contains(c.User.Identity.Name)));
Then:
[Authorize(Policy = "MustBeJoeOrBob")]
However, if it isn't clear, this requires a fair bit of hard-coding and you'd need a separate policy for each distinct group of users. For example, if a different action could only be accessed by Joe and Mary, but not Bob, then you'd need to add a "MustBeJoeOrMary" policy, too. That can get tedious quick.
There is technically a way to have one policy handle any given list of users, but implementation is non-trivial. You essentially have to create custom AuthorizeAttribute, which then allows you to pass different kinds of data. However, the actual authorization still needs to be policy-based, so you basically just map passed in value to a custom policy name with a standard prefix. For example:
public class UsersAuthorizeAttribute : AuthorizeAttribute
{
private const string PolicyPrefix = "MustBeUsers"
public UsersAuthorizeAttribute(string users)
{
Users = users;
}
public string Users
{
get => Policy.Substring(PolicyPrefix.Length);
set => $"{PolicyPrefix}{value}";
}
}
Then, you can apply the attribute like:
[UsersAuthorize("Joe,Bob")]
This effectively just does the same thing as:
[Authorize(Policy = "MustBeUsersJoe,Bob")]
In other words, it's just a short hand way of creating a "dynamic" policy name. However, you now need a policy handler, so you're either back in the same boat of creating one for every possible combination of users, or you have to create a custom policy provider. That policy provider then can look at just the prefix, "MustBeUsers", and use something like a MustBeUsersAuthorizationHandler to satisfy the policy, passing in the rest of the policy name (i.e. the actual usernames) into the handler for it to do it's evaluation on. However, ASP.NET Core will only use one policy provider, so once you sub in a custom one, you also need to ensure that it supports other policies, as well, or at least delegates policy handling to a default provider internally. The docs go into greater detail, but suffice to say, you can start to get into the weeds quick.
Honestly, this whole approach feels like a huge hack, and I'm actually very surprised that the docs actually describe how to achieve it in detail. If you really need something like this, it might make sense, but in your scenario, I think you're missing a crucial thing: you can just use roles.
If you want only Joe and Bob to be able to access a particular action, then simply create a role and assign them to that. Then specify that role:
[Authorize(Roles = "JoeAndBobsRole")]
This is what roles are intended for, and you're essentially trying to side step that and implement the same functionality in a different way. That's honestly probably why Users doesn't exist as an option in ASP.NET Core in the first place.
We have an ASP.NET Web API app which uses Ninject for DI. This works perfect for use. One of the improvements we were considering is the ability to swap out parts of functionality per request based on some sort of unique identifier.
Example. Two customers use our restful api. Both get the same functionality. A third customer has paid for the super version of our api. He makes the request, we load the super dll and bind the super implementations to the standard interfaces.
Essentially what I am looking to see is can we load a DLL and swap out bindings per request using Web API and Ninject.
EDIT:
So both answers are correct for the original question but my intention is different and it is my fault for not explaining it correctly. What we have is a base layer of functionality that everyone gets. On top of this we also have the ability to implement custom logic on a per customer basis that overrides this functionality. This logic is stored as a DLL in Azure Blob Storage.
What we would like to do is when a customer makes a request is go get the DLL, bind all the custom services and then service the request using these new bindings.
Is hot swapping not the best way to do this? We are new enough to ninject so this may be a common thing that is implemented in a different way to what we are considering.
To some up, we would like to be able to service custom bindings on a per customer basis.
EDIT 2:
We use conditional bindings for items were we know that we have alternate implementations but in the scenario above until we get the customer info and scan the dll we do not know if we have alternate bindings. We don't even know if there is a dll.
We would like to do it this way so we can drop the file in rather than referencing it in the project.
I don't mind that you can swap out bindings per request. But what you can do is to use conditional binding.
Example - default bindings:
protected override Ninject.IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IAuthorizationService>()
.To<AuthorizationService>()
.InRequestScope();
kernel.Bind<IService>()
.To<BasicService>();
return kernel;
}
It will inject (on place where IService is needed) a BasicService for some basic user and ExtraService for VIP user.
For more information about various ways of conditional binding see Ninject - Contextual binding.
EDIT
I think you can still use conditional binding. You will only need to propagate the IKernel to place where you want to register components from new dll. For example I have this in my global.asax for dynamically loading dll modules - it runs on app startup.
Loading modules:
private void LoadAssemblies(IKernel kernel) {
foreach (var fileName in Directory.GetFiles(Server.MapPath("~/App_Data"), "*.dll")) {
Assembly loadedAssembly = Assembly.LoadFile(fileName);
try {
var moduleRegistrations = loadedAssembly.GetTypes()
.Where(t => t.IsClass && t.IsAbstract == false && typeof (IMyModuleRegistration).IsAssignableFrom(t));
foreach (var moduleRegType in moduleRegistrations ) {
IMyModuleRegistration moduleReg = (IMyModuleRegistration) Activator.CreateInstance(moduleRegType);
moduleReg.RegisterComponents(kernel);
}
}
catch (ReflectionTypeLoadException exception) {
....
}
}
}
Module definition:
public class MyExtraModule : IMyModuleRegistration
{
public void RegisterComponents(IKernel kernel)
{
kernel.Bind<IService>()
.To<ExtraService>()
.When(x => x.ParentContext
.Kernel.Get<IAuthorizationService>()
.IsVIPUser());
}
}
ExtraService will be used only when dll with MyExtraModule is loaded.
EDIT 2
You can download that dll from somewhere. Load it and then test it if it implements your registration interface. Then call that registration and you are done. The only problem I see is: where to store the reference to IKernel - probably some static property in HttpApplication will be enough. You should also track already loaded dlls.
Or in later versions of Ninject I can suggest extending the NinjectModule and then load it into kernel with kernel.Load(..) method. Look at this Modules and kernel - specially in part Dynamic Module Loading - maybe it is what you are looking for.
Use conditional bindings:
Bind<IMyService>().To<MyService>();
Bind<IMyService>().To<MyServiceForVIPs>().When(ctx => CurrentPrincipalIsVIP());
I assume that you know the core ninject modules. You can load all core ninject modules into the kernel. When the special user arrives you could unload the core module und load the user specific module into the kernel.
A better approach would be to have a special kernel in the plugin area. So actually a kernel per plugin approach wich loads the required core modules and adds the user specific ones if any. But that might have performance impacts!
After my wonderings on the events registration (you can find here ViewModel Event Registration and ViewModel Lifetime), now I'm thinking about viewmodel tombstoning:
In case of Tombstoning, is the ViewModel serialization a good approach ?
I'm thinking about the case in which different viewmodels have a reference to the same class. In case of Viewmodels serialization and deserialization the referenced class instance could have duplicated instance, isn't it ?
Wouldn't be better to have specialized state classes whose unique purpose in to contain all the app data, everyviewmodel get data (i mean reference to the data) from there and update the data in there and the app think only to serialize those specialized class ?
Any experience on this subject is appreciated.
Regards
SkyG
Caliburn Micro has a lot of this built in to the framwork allowing you to save properties of a view model or the entire graph to both phone state and app settings. You just need to create a class and inherit from StorageHandler.
public class PivotPageModelStorage : StorageHandler<PivotPageViewModel>
{
public override void Configure()
{
this.ActiveItemIndex().InPhoneState().RestoreAfterViewLoad();
}
}
And to your other posted question. CM has a nice way of handling the forced view first approach on the phone. It allows you to do page navigation by specifying the VM and it will handle the rest. And as a bonus, if you specify parameters to pass CM will pull them off the query string and populate properties on the target VM.
public void GotoPageTwo()
{
navigationService.UriFor<PivotPageViewModel>().WithParam(x => x.NumberOfTabs, 5).Navigate();
}
I am attempting to write a custom membership class. It seems to work ok inhering the Membership class and providing functions for all the included required items (validate user, create user, delete user, isapproved, etc).
However, where I run into a problem is when I try to add properties or methods.
As all the other properties and methods are public override classes in a sealed class,
the additional properties do not show up.
Say for example (example only, not "real" code):
public sealed class Membership : MembershipProvider
{
public override string ApplicationName
{
get
{
return "myApp";
}
}
public string myValue { get;set;}
}
Now, I understand why myValue will not show up when I try to do Membership.myValue but Membership.ApplicationName will.
My question is, how to extend membership to show the custom items? Do I ditch Membership.xxx entirely and write a wrapper class? If so, how? I can find all the documentation in the world on how to create a custom membership class. I've got a working custom membership that works fine if I use all the available options only. I've got a custom roles provider and a custom config section to store everything and it's best friend.
What I don't have is an elegant solution.
I'd like the end result to be that I use one reference (such as Membership.xxx or myClass.xxxx) to reference all membership items + custom items.
Please provide examples of how to implement or links to appropriate items that will resolve the custom methods item.
Any time you reference the membership instance you will just have to cast it to your class type, that's all.
You can take a look at Extension Methods if you don't want to cast back and forth your instances