I am trying to learn MVC 3/4 using visual studio 2012. I have created a view, a model and controller. VS created all the database stuff for me. It added a gridview for me where I can add a new row, edit or delete too. I would like to change the way it selects the rows from the database. I know that I have to change the DbContext for that.
here is my DbContext,
public class ApartmentContext : DbContext
{
public ApartmentContext() : base("name=ApartmentContext")
{
}
// this part has to be changed****
public DbSet<Apartment> Apartments { get; set; }
}
public DbSet Apartments{...} returns the list I guess, but I want to change the way it selects the rows. For example; I want to select the rows whose "flag" column is set to 1. how do I do that?
thanks
You should filter your results in the related controller, not in the DbContext. It could be like this in that controller:
...
ApartmentContext db = new ApartmentContext();
var apartments = db.Apartments.Where(a => a.Flag == 1);
...
and then use apartment object to render your view
You need to create query. Object Apartments represents table in database, not a list.
You can also use entity framework dbconext to execute your TSQL Statement or stored procedure. Following is a link for that.
http://www.dotnetjalps.com/2012/04/execute-tsql-statement-with.html
An alternative is to have a wrapping interface around the context to hide these details, so that is applies to every query transparently:
// Wrapping interface
public interface IApartmentRepository
{
IQueryable<Apartment> Apartments { get; }
}
// As before
public class ApartmentContext : DbContext
{
...
}
// Implementing class, hiding the DbContext object
public class EFApartmentRepository : IApartmentRepository
{
private ApartmentContext context = new ApartmentContext();
public IQueryable<Apartment> Apartments
{
get { return this.context.Apartments.Where(a => a.Flag == 1); }
}
}
// Your controller uses DI to get the controller
public class HomeController : Controller
{
private IApartmentRepository apartmentContext;
public HomeController( IApartmentRepository rep )
{
this.apartmentContext = rep;
}
}
The controllers IApartmentRepository parameter can be hooked up to the EFApartmentRepository by overidding the DefaultControllerFactory class. You use a DI framework like NInject or StructureMap to insert the correct implementation into the constructor at runtime.
Related
I am using Caliburn.Micro in combination with Xamarin.Forms. Within my App class, I register an interface ILicenseInfo with a class LicenseInfoImplementation via the SimpleContainer's PerRequest method.
CM then injects an object when my view model is created (see ViewModelOne) which is what I want. However, I don't see how I can extend this to a collection of objects. Lets say I would like CM to instantiate ViewModelTwo which expects a collection of object. How would I have to change App.cs and the XAML of ViewModelTwo to make that happen?
public partial class App : FormsApplication
{
private readonly SimpleContainer _container;
public App (SimpleContainer container)
{
InitializeComponent();
this._container = container;
// register interface and class
_container.PerRequest<ILicenseInfo, LicenseInfoImplementation>();
//....
}
}
public ViewModelOne(ILicenseInfo license)
{
// Great, Caliburn.Micro injects an LicenseInfoImplementation object
}
public ViewModelTwo(IEnumerable<ILicenseInfo> licenses)
{
// No idea
}
I finally used the following pattern. Not the most elegant way to do it but the best I found ...
public ViewModelTwo() : base (IoC.GetAll<ILicenseInfo>())
{
}
public ViewModelTwo(IEnumerable<ILicenseInfo> licenses)
{
// Do something with licenses
}
I'm using Unity.MVC for DI in my ASP.NET MVC 4.6 app. I have a service interface passed into the controller and that's working great. Now I want to pass in an interface to the EF context to the service but I'm not sure how to do this. I've read EF has this IObjectContextAdapter that I could pass into my service ctor and that works, but I need to then query the actual tables on inside my service from this context but because it's an IObjectContextAdapter it doesn't know my tables. How do I do this?
public class ContactService : IContactService
{
//private ContactsEntities context;
private IObjectContextAdapter context;
// test ctor
public ContactService(IObjectContextAdapter ctx)
{
context = ctx;
}
// prod ctor
public ContactService()
{
context = new ContactsEntities();
}
List<Contact> GetAllContacts()
{
return (from c in context.ObjectContext.?? // I need to query the Contacts table that would be attached to the actual context I pass in but still keep the decoupling from using an Interface passed into the ctor
}
}
The IObjectContextAdapter is the type of ObjectContext property of DbContext.
You should subclass DbContext e.g. ContactsDatabaseContext
public class ContactsDatabaseContext : DbContext, IContactsDatabaseContext
{
// ...
}
And then just register your ContactsDatabaseContext with your IoC container. Something like this:
container.RegisterType<IContactsDatabaseContext, ContactsDatabaseContext>();
Your ContactsDatabaseContext class and IContactsDatabaseContext interface should have properties of type DbSet<T> that refer to your tables e.g.:
IDbSet<BrandDb> Users { get; set; }
UPDATE:
Since you are using a generated file, then do this:
public partial class ContactsDatabaseContext : IContactsDatabaseContext
{
// Expose the DbSets you want to use in your services
}
I am trying to migrate an MVC 5 Application to ASP.NET 5 MVC 6 (Beta 7).
Having problems when using the #inherits and #model directive together.
Works fine when they are used separately.
In my _ViewImports i added the #inherits directive to use a base page with some custom user properties.
public abstract class BaseViewPage<TModel> : RazorPage<TModel>
{
protected MyPrincipal AppUser
{
get
{
return new MyPrincipal(this.User as ClaimsPrincipal);
}
}
}
_ViewImports.cshttml
#inherits CommonWeb.BaseViewPage<TModel>
#addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
And then i can go AppUser. in all my views.
This works if i dont use a strongly typed view. If i add the #model directive in any view the inherited view page goes away.
Help appreciated
Update:
I did this successfully by using a custom pageBaseType in the web.config in prior versions.
Workaround.
public class ViewHelper
{
ViewContext _context;
public ViewHelper(ViewContext context)
{
_context = context;
}
public MyPrincipal AppUser
{
get
{
return new MyPrincipal(_context.HttpContext.User as ClaimsPrincipal);
}
}
public string ControllerName
{
get
{
return _context.RouteData.Values["controller"].ToString();
}
}
}
View:
#{ var viewHelper = new ViewHelper(ViewContext);}
A way to achieve this for all views?
There is a better way in MVC 6, which now supports injecting dependencies on the views with the #inject directive. (The directive #inject IFoo Foo allows you to use in your view a property named Foo of type IFoo)
Create a new interface IAppUserAccessor for getting your app user, for example:
public interface IAppUserAccessor
{
MyPrincipal GetAppUser();
}
Create a class AppUserAccessor implementing it:
public class AppUserAccessor : IAppUserAccessor
{
private IHttpContextAccessor httpContextProvider;
public AppUserAccessor(IHttpContextAccessor httpContextProvider)
{
this.httpContextProvider = httpContextProvider;
}
public MyPrincipal GetAppUser()
{
return new MyPrincipal (
httpContextProvider.HttpContext.User as ClaimsPrincipal);
}
}
Register the new interface in the services container by adding a new entry in the ConfigureServices method of Startup.cs:
services.AddTransient<IAppUserAccessor, AppUserAccessor>();
Finally use the #inject directive to inject the IAppUserAccessor in your views. If you add the directive in ViewImports.cshtml then it will be available on every view.
#inject WebApplication4.Services.IAppUserAccessor AppUserAccessor
With all the pieces above you can now just use it on your view(s):
#AppUserAccessor.GetAppUser()
Update
If you need to inspect the route values, like the controller name, you can inject an IActionContextAccessor into your class and use it as follows:
public AppUserAccessor(IHttpContextAccessor httpContextProvider, IActionContextAccessor actionContextAccessor)
{
this.httpContextProvider = httpContextProvider;
this.actionContextAccessor = actionContextAccessor;
}
...
public string ControllerName
{
get { return actionContextAccessor.ActionContext.RouteData.Values["controller"].ToString(); }
}
Of course, that doesn't look like an AppUserAccessor anymore and smells like it has different responsabilities. At the very least it needs a more appropriate name :)
I would double check what do I need the controller name for. There might be a better way to accomplish your objective. (For example, if you need it for generating new links/urls you might just use an IUrlHelper)
Accessing ViewContext
Looks like beta8 has added support for injecting the ViewContext, although the implementation details may change before RC. See this question
I am wanting to create a Model that has a property of Service which then has multiple options that can either be true or false. So my Contact Class:
public class Contact
{
//My Properties
}
I want the Contact class to have a property of Services. I have a list of services available. How can I reference my services from my Contact class. I would like be able to access it in my view like: model.services.MyCustomService if it's even possible. I come from a javascript background so this is what I mean but written in javascript if it helps.
Javascript Example
var Contact = {
property: "",
services: {
MyCustomService: "",
MyCustomService2: "",
}
}
Here's how I'd do it:
In your Model:
public class Contact
{
//My Properties
public List<Service> Services
{
get;
set;
}
}
In your Controller:
public ActionResult Index()
{
var model = new Contact(); // Create model
// Create some sample services
var service = new Service();
var service2 = new Service();
// Add the services
model.Services.Add(service);
model.Services.Add(service2);
// Pass the model to the view
return View(model);
}
Then, in your view:
#model MySite.Models.Contact
#foreach (var service in Model.Services)
{
<text>Here's my service: #service.MyCoolProperty.ToString()</text>
}
In that simple example, I first declared the Services property of your Contact class as a List<Service>. That allows you to combine many Services into one property - perfect for passing along to a view.
Next, in the Controller, I added some Services to the List by using the Add() method. Therefore, in the View, you're now able to access those Services through Model.Services.
To me, that looks like one of the simplest ways to approach this common problem. Hope that helped!
In C#, every object has a type so Services property has to have an actual type if you want to reference MyCustomService and MyCustomService2 through dot notation:
class Contact {
public ServiceContainer Services { get; set; }
}
class ServiceContainer {
public Service1 Service1 { get; set; }
public Service2 Service2 { get; set; }
}
However, if container serves for no other purpose but to store a service (assuming it's some object), you should probably store them in a list or array (access by index) or in a dictionary (access by string).
To give you more information, I'll need to know what exactly these services are, whether you expect their set to change, do they have different types, etc.
To bind to a collection all you need is this:
<%# Page Inherits="ViewPage<IList<Book>>" %>
A complete explanation can be found here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
This is my first try using DI, I've chosen ninject for it's reportedly easy learning curve, and have this question.
I'm creating objects like this:
var registrants = JsonConvert.DeserializeObject<List<Registrant>>(input);
I currently have this constructor for Registrant
[Inject]
public Registrant(IMemberRepository memberRepository)
{
_memberRepository = memberRepository;
}
What is the best way to have the repository dependency be injected into the deserialized object(s) using Ninject?
You can't use constructor injection with objects that are not created by Ninject (e.g. deserialized objects). But you can use property injection. Just call kernel.Inject(obj)
One question that remains is why you want to inject those objects. Normally, you don't want to use depedency injection on data container objects. In a proper design they don't have any dependency on services. The operations that need to be done on the services are done by the owner of the data container objects. I recommend to consider a refactoring of your design.
Assuming you're using Ninject V2, and you're using it in the context of an ASP.NET app, you should be using Ninject.Web to do the hookups.
Then you set up a Global class with the Factory Method support hooked in:
public class Global : NinjectHttpApplication
{
protected override Ninject.IKernel CreateKernel()
{
var kernel = new StandardKernel( new Module() );
kernel.Components.Add( new FuncModule( ) );
return kernel;
}
}
that registers the module that will Bind IMemberRepository to something:
public class Module : NinjectModule
{
public override void Load()
{
Bind<IMemberRepository>().To<MemberRepository>();
}
}
and the page wires up like this:
public class ThePage : PageBase
{
readonly Func<Registrant> _createRegistrant;
public ThePage( Func<Registrant> createRegistrant )
{
_createRegistrant = createRegistrant;
}
private void OnCreateRegistrant()
{
var newRegistrant = _createRegistrant();
}
}
NB not 100% sure if constructor injection is supported for Web Forms pages or wheter the above needs to drop to property injection... anyone?
(assuming the classes you have are as follows:)
public class MemberRepository : IMemberRepository
{
}
public interface IMemberRepository
{
}
public class Registrant
{
private readonly IMemberRepository _memberRepository;
public Registrant( IMemberRepository memberRepository )
{
_memberRepository = memberRepository;
}
}