someone know how to retrieve the ApbSession in a mvc view??
i've tried with a session, or accessing the controllers that have the session injected, but there's no way to get the currentSession to get the userId and other properties.
The Asp.net Session is not valid, because ApbSession dont work with it.
Thanks in advice.
I suggest you to get needed values in the controller then pass to the view via viewmodel. However, if you need to access to AbpSession you have different ways depending on the ASP.NET version you are using.
For ASP.NET Core, use #inject IAbpSession AbpSession in the razor view and directly use it.
For ASP.NET MVC 5.x, use property injection in your view base (YourProjectNameWebViewPageBase like that: https://github.com/aspnetboilerplate/module-zero-template/blob/master/src/AbpCompanyName.AbpProjectName.WebMpa/Views/AbpProjectNameWebViewPageBase.cs). Alternatively, you can use IocManager.Instance.Resolve<IAbpSession>()... wherever you need.
Following the suggestion of hikalkan above, here it is the code to add it in class [YourApplication]WebViewPageBase<TModel>:
public abstract class YourAppWebViewPageBase<TModel> : AbpWebViewPage<TModel>
{
// Gp
public IAbpSession AppSession { get; private set; }
protected YourAppWebViewPageBase()
{
LocalizationSourceName = YourAppConsts.LocalizationSourceName;
// Gp - added the AbpSession in the view
AppSession = Abp.Dependency.SingletonDependency<IAbpSession>.Instance;
}
}
Related
I'm trying to inject a second repository into my asp.net mvc 3 controller. And I cant get it to work, not sure where to "add another" using Ninject.
I have a void function in global.asa.cs
kernel.Bind<INewsRepository>().To<NewsRepository>();
And in my controller I have:
private INewsRepository _newsRepository;
private IContentRepository _contentRepository;
public NewsController(INewsRepository newsRepository, IContentRepository contentRepository)
{
this._newsRepository = newsRepository;
this._contentRepository = contentRepository;
}
How can I register IContentRepository for the NewsController as well?
I use autofac instead of Ninject but the basics stay the same.
If you got your first dependency injection working then you should be able to bind others as well. You just have to add a new binding in Application_Start() in your Global.asax.
So under your first binding do this as well:
kernel.Bind<IContentRepository>().To<ContentRepository>();
You can have as many bindings as you like.
First off it's a good practice to move the bootstrapping of your application into a separate location. This keeps your Global.asax clean.
You should also be using convention based registration. It will end up saving you lots of time for the bindings you don't need to customize.
So for you I'd probably suggest the following
public static class Bootstrapper()
{
public static void Bootstrap()
{
kernel.Scan( k =>
{
k.FromAssemblyContaining<INewsRepository>();
k.BindWithDefaultConventions();
});
}
}
And in your Global.asax you add this..
Bootstrapper.Bootstrap();
Then I would suggest you spend some time on Google reading about ninject conventions.
What's a good way to validate a model when information external to the model is required in order for the validation to take place? For example, consider the following model:
public class Rating {
public string Comment { get; set; }
public int RatingLevel { get; set; }
}
The system administrator can then set the RatingLevels for which a comment is required. These settings are available through a settings service.
So, in order to fully validate the model I need information external to it, in this case the settings service.
I've considered the following so far:
Inject the service into the model. The DefaultModelBinder uses System.Activator to create the object so it doesn't go through the normal dependency resolver and I can't inject the service into the model without creating a new model binder (besides which, that doesn't feel like the correct way to go about it).
Inject the service into an annotation. I'm not yet sure this is possible but will investigate further soon. It still feels clumsy.
Use a custom model binder. Apparently I can implement OnPropertyValidating to do custom property validation. This seems the most preferable so far though I'm not yet sure how to do it.
Which method, above or not, is best suited to this type of validation problem?
Option 1 doesn't fit. The only way it would work would be to pull in the dependency via the service locator anti-pattern.
Option 2 doesn't work. Although I couldn't see how this was possible because of the C# attribute requirements, it is possible. See the following for references:
Resolving IoC Container Services for Validation Attributes in ASP.NET MVC
NInjectDataAnnotationsModelValidatorProvider
Option 3: I didn't know about this earlier, but what appears to be a very powerful way to write validators is to use the ModelValidator class and a corresponding ModelValidatorProvider.
First, you create your custom ModelValidatorProvider:
public class CustomModelValidatorProvider : ModelValidatorProvider
{
public CustomModelValidatorProvider(/* Your dependencies */) {}
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
if (metadata.ModelType == typeof(YourModel))
{
yield return new YourModelValidator(...);
}
}
}
ASP.NET MVC's IDependencyResolver will attempt to resolve the above provider, so as long as it's registered with your IoC container you won't need to do anything else. And then the ModelValidator:
public class EntryRatingViewModelValidatorMvcAdapter : ModelValidator
{
public EntryRatingViewModelValidatorMvcAdapter(
ModelMetadata argMetadata,
ControllerContext argContext)
: base(argMetadata, argContext)
{
_validator = validator;
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
if (/* error condition */)
{
yield return new ModelValidationResult
{
MemberName = "Model.Member",
Message = "Rating is required."
};
}
}
}
As the provider is retrieved through the IDependencyResolver and the provider has full control over the returned ModelValidators I was easily able to inject the dependencies and perform necessary validation.
You could try fluent validation. It supports asp.net mvc and DI so you can inject external services into your validators.
Assuming that you want both client and server-side validation of the model based upon the values returned from the service, I would opt for 2., Inject the service into an annotation.
I give some sample code in my response to this question about adding validators to a model. The only additional step in your case is that you will need to inject your service into your class inheriting from DataAnnotationsModelValidatorProvider.
What about just simply using IValidateableObject and in that method determine if validation is appropriate or not and setting the errors there?
How do I use IValidatableObject?
I customize IIdentity and IPrincipal adding a few more properties in IIdentity.
You can obtain a strongly typed instance #User.Identity for my custom class? Without having to make conversions in cast.
I thought of something like razor customize the View, but do not even know where to start.
You could try creating an extension method on IPrincipal
public static class PrincipalExtensions
{
public static MyIdentity GetMyIdentity (this IPrincipal principal)
{
return principal.Identity as MyIdentity;
}
}
and then get your identity by calling #User.GetMyIdentity()
You could create a new base type for your views and add to it a property or method that will do the casting. That way you can avoid doing it all the time in your views.
I'm [finally!] tackling MVC (version 3) after years of ASP.NET forms development. I have a strong background in n-tier application architecture, and I'm trying to approach this new project properly, with a clear separation of concerns, etc.
What I've done is start out with code-first by creating my POCOs. From this, the framework created my database.
Then, I implemented the Repository pattern by putting all my EF query and CRUD methods in a Repository class for each of my POCO classes in my Models assembly. This way, my Controllers don't need to know a thing about how I access my data via the EF. Great.
Finally, I created a few ViewModel classes in my Models assembly. My intent is, for certain actions (such as create and edit), I reference my ViewModel classes from the RAZOR views, instead of my POCO classes. This way, I can have my POCO class as well as a SelectList for populating a Drop Down within my ViewModel. Both populated by references to the associated Repository classes, which are called from my Controller Actions. I think I'm on a roll now:
class MyObject
{
public int ID {get;set}
[Required]
[StringLength(512)]
public string Name {get;set;}
}
class MyViewModel // ViewModel for a specific view
{
public MyObject MyModel {get;set;} // the model that is being edited
// other data the view might need, set by the controller
public string SomeMessage { get; set; }
public List<SomeObject> SomeObjects {get;set;} /// e.g. for a drop-down list
// My constructor below that populates the "SomeObjects" list, and accepts the
// "MyObject" class as a parameter in order to set the "MyModel" property above...
// ..........
}
The Problem...
Before I started using my ViewModel classes from my Controller Create and Edit actions, I passed in the POCO class directly. Everything worked fine when I hit the save button from my Edit form within my view:
Old Code:
[HttpPost]
public ActionResult Edit(MyObject mine)
{
if (ModelState.IsValid)
{
myRepository.Update(mine);
myRepository.SaveChanges();
return RedirectToAction("Index");
}
return View(mine);
}
When I hit save, my POCO class (MyObject) would be returned, automagically populated with values from the form, it would successfully save, and life was peachy.
When I switched to passing in my ViewModel (MyViewModel), everything fell apart.
I was able to refer to my ViewModel (MyViewModel) by setting the #model reference at the top of my Edit view. I was then able to populate my form fields from my POCO class (MyObject) that is part of the ViewModel. I was even able to populate the DropDownList from the SomeObjects collection in the ViewModel and preselect the correct one from my MyObject class I was editing. Everything seemed fine UNTIL...
When I hit the save button and my Controller's Edit ActionResult (POST action) was called, the MyObject class that is passed in to the ActionResult (public ActionResult Edit(MyObject mine)) was null.
Then, I tried changing the passed in object to my ViewModel (public ActionResult Edit(MyViewModel myVM)), which had the referenced MyObject class (MyModel) as null.
What am I missing?
I know it has to be something so incredibly simple that it's staring me in the face and I cannot see it!
Look at the FormCollection, the names of the keys should match the properties of the class you want to fill. This is how the default modelbinding of MVC works.
Wim,
Thanks so much for your help. I did have s parameter-less constructor, I had just omitted it from the example.
I actually tracked down the issue. In all fairness, the code I typed in was not the actual code since I didn't have it in front of me when I posted this. What the issue was is that my entity model class reference in my ViewModel actually had its set accessor as private:
public MyObject MyModel {get;private set;}
This had prevented the modelbinder from populating that property when posting back during the controller's save method.
What I'm left to do now is to move my validation logic from my EF POCO to my ViewModel, as seems to be the recommended action in this type of pattern.
Thanks for your time, and I hope this helps out other people with similar issues who are new to this framework.
Learning ASP.NET MVC with a new project, and a little unsure of where some things should happen. I've read that ViewModels are a Good Thing (tm) and had planned on doing it in a similar fashion anyway, but I'm still not entirely clear on the responsibilities of the Model vs. the Controller.
Should the ViewModel be responsible for actually loading itself from the ORM? Thus the controller would just call ViewModel.GetObject() and pass the result back to the view?
Or should I load the data in the Controller, and then transform it into the ViewModel? Seems like that puts a lot of work in the Controller though, which is supposed to be kept somewhat lightweight.
I guess I could also have a third party that is responsible for pulling the data, then the Controller would call that and transform it for the appropriate ViewModel.
So any thoughts on what is the "best" approach?
The controller will create the viewmodel object and fill it out using the model. The model should use the ORM to get the data.
The ViewModel is always specific to the view only, and the model is specific to the domain. In CQRS you would actually just get the ViewModel and send it to the view.
From the controller you can do what ever it takes to make your CRUD happen for the view. If you use the Repo pattern thats ok, if you use NHibernate or EF directly thats cool tool. Once the ViewModel goes to the view it will be disconnected from everything like the DB, so fill it out before it gets there.
Personally I use a repository. So the controller queries a repository and gets a model, then maps the model to a view model and passes the view model to the view. Example:
public class ProductsController: Controller
{
private readonly IProductsRepository _repository;
private readonly IMapperEngine _mapper;
public ProductsController(IProductsRepository repository, IMapperEngine mapper)
{
_repository = repository;
_mapper = mapper;
}
public ActionResult Index(int id)
{
Product product = _repository.GetProduct(id);
ProductViewModel viewModel = _mapper.Map<Product, ProductViewModel>(product);
return View(viewModel);
}
}
And because this is repetitive logic I use custom action filters:
public class ProductsController: Controller
{
private readonly IProductsRepository _repository;
public ProductsController(IProductsRepository repository)
{
_repository = repository;
}
[AutoMap(typeof(Product), typeof(ProductViewModel))]
public ActionResult Index(int id)
{
Product product = _repository.GetProduct(id);
return View(product);
}
}
in this case the custom action filter intercepts the result of the action and replaces it using the corresponding mapping layer.
The way this repository is implemented is not the responsibility of the controller (whether it is an ORM, direct SQL queries, or even distant web service calls). As long as it is injected some proper implementation it will work which allows for weaker coupling between the different parts of the application and easier unit testing in isolation. So in this example it is the implementation of the repository that is responsible for fetching data.