I am trying to use MVC with a controller a view a model and the database.
But I premise I do not know how to use entity framework in my case to connect the model and the database. So I get this runtime error:
"InvalidOperationException: Unable to resolve service for type 'WebCoreFly.Models.FlightsList' while attempting to activate 'WebCoreFly.Controllers.HomeController"
My code consists in:
the controller code:
public class HomeController : Controller
{
private FlightsList l;
public HomeController(FlightsList theList)
{ l = theList; }
public ViewResult Index()
{
return View(l.Flights);
}
}
the Model Code for Flights:
public partial class Flights
{
public long ID { get; set; }
public long Id_Destination { get; set; }
public string Id_Source { get; set; }
public string Nome { get; set; }
public string Company { get; set; }
public System.DateTime Time { get; set; }
public string Id_Plane { get; set; }
public Nullable<System.DateTime> TimeOfArrival { get; set; }
}
and the model for FlightsList:
public class FlightsList
{
private FlyDBContext context;
public FlightsList(FlyDBContext ctx)
{
context = ctx;
}
public IQueryable<Flights> Flights => context.Flights;
}
finally I have defined my dbcontext:
public class FlyDBContext : DbContext
{
public FlyDBContext(DbContextOptions<FlyDBContext> options)
: base(options)
{
}
public DbSet<WebCoreFly.Models.Passengers> Passengers { get; set; }
public DbSet<WebCoreFly.Models.Bookings> Bookings { get; set; }
public DbSet<WebCoreFly.Models.Flights> Flights { get; set; }
}
And in my startup code, I configure services to accept my dbcontext with a link to Existing SQL Database called Fly:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<FlyDBContext>(options =>
options.UseSqlServer(#"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Fly;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"));
}
And this is the Configure method of startup:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
My question is: who is responsible to pass to my controller the flights list? and since the flightlist is tied to the dbcontext, is the problem somehow related to the fact I did not use entityframework? (For semplicity Idid not post the code for my view, but I can do it if necessary)
the issue is coming because of the dependency Injection. Here How the application would know that Flights List object requires in Home Controller. To fix this you have to configure it in StartUp.Cs class Configure Service method.
services.AddSingelton<FlightsList>();
There are various ways to configure it like Transient, AddScoped etc.
It is better if you use repository pattern here. Register here the Interface. like following.
services.AddSingelton<IRepository, FlightsList>();
In controller side.
public class HomeController : Controller
{
private IRepository l;
public HomeController(IRepository theList)
{ l = theList; }
public ViewResult Index()
{
return View(l.Flights);
}
}
Hope it will help.
Related
am a beginner in ASP.NET Core. I am creating a Web API service. While I am fetching the data from the database, I had a problem. What is the error I got? I have successfully done the database migration part and created the database successfully.
StudentDbContext is null
StudentController
namespace webb.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class StudentController : ControllerBase
{
private StudentDbContext studentDbContext;
public StudentController(StudentDbContext studentDbContext)
{
studentDbContext = studentDbContext;
}
// GET: api/<EmployeeController>
[HttpGet]
public IEnumerable<Student> Get()
{
// var studens = studentDbContext.Student;
return studentDbContext.Student;
}
}
}
Model
public class Student
{
public int id { get; set; }
public string stname { get; set; }
public string course { get; set; }
}
}
StudentDbContext
public class StudentDbContext : DbContext
{
public StudentDbContext(DbContextOptions<StudentDbContext> options) : base(options)
{
}
public DbSet<Student> Student { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=ams;Integrated Security=True; TrustServerCertificate = True");
}
}
IDataService
public interface IDataService<T>
{
Task<IEnumerable<T>> GetAll();
Task<T> Get(int id);
Task<T> Create(T entity);
Task<bool> Delete(T entity);
Task<T> Update(T entity);
}
}
I have successfully done the database migration part and created the
database successfully. StudentDbContext is null
Well, two mistake has been done. Your model has no primary key. So you will always get null data when there is no primary key set to your table column.
Therefore, your model should be as following:
Model:
public class Student
{
[Key]
public int id { get; set; }
public string stname { get; set; }
public string course { get; set; }
}
Controller:
Another misake is here studentDbContext.Student; this will not bring anything. You would be liking to fetch student list instead. So you should write studentDbContext.Student.ToList();. As following"
[HttpGet]
public IEnumerable<Student> Get()
{
// var studens = studentDbContext.Student;
return studentDbContext.Student.ToList();
}
Note: In addition, your constructor convension is not correct, it can be written as following:
[Route("api/[controller]")]
[ApiController]
public class StudentController : ControllerBase
{
private readonly StudentDbContext _studentDbContext;
public StudentController(ApplicationDbContext studentDbContext)
{
_studentDbContext = studentDbContext;
}
// GET: api/<EmployeeController>
[HttpGet]
public IEnumerable<Student> Get()
{
// var studens = studentDbContext.Student;
return _studentDbContext.Student.ToList();
}
}
Note: You can check more details on asp.net core web api official document here
Output:
For further details you can have a look on official document here.
I'm fairly new to razor pages Asp.Net MVC Razor pages,
I created a model with the user fields and wanted to fill it with data once i logged in and access that same data in other pages by calling on the model instead of making another db call
This is my code currently
Model:
public class Utilizador
{
[Key]
public int id { get; set; }
[Required, MaxLength(100)]
public string username { get; set; }
[Required, MaxLength(100)]
public string email { get; set; }
[Required, MaxLength(100)]
public string password { get; set; }
}
then i added a sigleton to Program.cs
builder.Services.AddSingleton<Utilizador>();
You can store your data in the Session or Cache during the first login verification, and then you can call the data directly from the Session without calling the database again.
My test code:
Utilizador.cs:
public class Utilizador
{
public int id { get; set; }
public string username { get; set; }
public string test { get; set; }
}
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddScoped<Utilizador>();
services.AddSession();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// other middleware
app.UseSession();
// other middleware
}
Test1.cshtml.cs:
public class Test1Model : PageModel
{
private readonly Utilizador _Utilizador;
private Utilizador model { get; set; }
public Utilizador getValue { get; set; }
public Test1Model(Utilizador Utilizador)
{
_Utilizador=Utilizador;
}
public async Task<IActionResult> OnGetAsync(int id)
{
if (id == 1)
{
_Utilizador.username = "MyTest";
_Utilizador.test = "Success";
}
else
{
_Utilizador.username = "MyTest";
_Utilizador.test = "Fail";
}
model = _Utilizador;
HttpContext.Session.Set<Utilizador>(id.ToString(),model);
getValue=HttpContext.Session.Get<Utilizador>(id.ToString());
return Page();
}
}
Get data directly from the corresponding page:
Test1.cshtml:
#page
#model CacheTest.Pages.TestPage.Test1Model
<div>#Model.getValue.username</div>
<div>#Model.getValue.test</div>
Test2.cshtml.cs:
public class Test2Model : PageModel
{
public Utilizador getValue { get; set; }
public void OnGet(int id)
{
getValue = HttpContext.Session.Get<Utilizador>(id.ToString());
}
}
Test2.cshtml:
#page
#model CacheTest.Pages.TestPage.Test2Model
<div>#Model.getValue.username</div>
<div>#Model.getValue.test</div>
Test Result
In Test1, store first and then read:
Directly read the data stored in the session in Test2:
You could try with EF Core,the official document:
https://learn.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/page?view=aspnetcore-6.0&tabs=visual-studio
https://learn.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/sql?view=aspnetcore-6.0&tabs=visual-studio
I'm new to ASP.NET Core and I have built an ASP.NET Core MVC with EF Core appplication using Code First approach when creating the database.
Now, I want to use DTOs and AutoMapper in this simple app.
In the code below you may find the Employee.cs from Models folder:
public class Employee
{
[Key]
public int EmployeeId { get; set; }
[Column(TypeName ="nvarchar(250)")]
[Required(ErrorMessage ="This field is required.")]
[DisplayName("Full Name")]
public string FullName { get; set; }
[Column(TypeName = "varchar(10)")]
[DisplayName("Emp. Code")]
public string EmpCode { get; set; }
[Column(TypeName = "varchar(100)")]
public string Position { get; set; }
[Column(TypeName = "varchar(100)")]
[DisplayName("Office Location")]
public string OfficeLocation { get; set; }
}
Below you may find the EmployeeController.cs file:
public class EmployeeController : Controller
{
private readonly EmployeeContext _context;
public EmployeeController(EmployeeContext context)
{
_context = context;
}
// GET: Employee
public async Task<IActionResult> Index()
{
return View(await _context.Employees.ToListAsync());
}
// GET: Employee/Create
public IActionResult AddOrEdit(int id = 0)
{
if (id == 0)
return View(new Employee());
else
return View(_context.Employees.Find(id));
}
// POST: Employee/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddOrEdit([Bind("EmployeeId,FullName,EmpCode,Position,OfficeLocation")] Employee employee)
{
if (ModelState.IsValid)
{
if (employee.EmployeeId == 0)
_context.Add(employee);
else
_context.Update(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(employee);
}
// GET: Employee/Delete/5
public async Task<IActionResult> Delete(int? id)
{
var employee =await _context.Employees.FindAsync(id);
_context.Employees.Remove(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
}
Additionally, you may find below the Startup.cs file:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<EmployeeContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DevConnection")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Employee}/{action=Index}/{id?}");
});
}
}
What changes should I make to my app in order to use DTOs and AutoMapper?
Please let me know whether you need other files from the app.
Thanks.
You can do following steps.
Create your EmployeeDTO.cs
public class EmployeeDTO
{
public int EmployeeId { get; set; }
public string FullName { get; set; }
public string EmpCode { get; set; }
public string Position { get; set; }
public string OfficeLocation { get; set; }
}
Install the corresponding NuGet package
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection
Note : If we install the AutoMapper.Extensions.Microsoft.DependencyInjection package, it will automatically install the AutoMapper package for us since it references it.
Create MappingProfile.cs
Add using AutoMapper;
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Employee, EmployeeDTO>();
CreateMap<EmployeeDTO, Employee>();
}
}
Configure the services. Let’s do it in the Startup.cs class.
services.AddAutoMapper(typeof(Startup));
First, we inject the mapper object into the controller. Then, we call the Map()method, which maps the Employee object to the EmployeeDTO object.
public class EmployeeController : Controller
{
private readonly EmployeeContext _context;
private readonly IMapper _mapper;
public EmployeeController(EmployeeContext context,, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
// GET: Employee
public async Task<IActionResult> Index()
{
List<EmployeeDTO> employees = _mapper.Map<List<Employee>, List<EmployeeDTO>>(await _context.Employees.ToListAsync());
return View(employees);
}
}
I'm following the repository pattern with service layers in my project.
For each view I'm going to create a viewmodel.
What I'm confused is that, should the service layer directly access domain objects and returns them to the controller, or should I use DTOs. If I should use DTOs, where to put them in the project architecture?
Thank you.
Service layer is responsible for mapping (converting) Dto objects and Domain objects by implementing proper business logic.
Your DTO objects should be used in controllers and services.
DTO's are transfered between Controller and Service, on the other hand Domain objects are transfered between Service and Repository
Controller does not know about Domain and Repository does not know about DTO. Service knows both DTO and Domain and converts them each other with business rules like a car between driver and road, like stackoverflow between you and me, like everything, abstraction...
Following code is an example. Consider each namespace is a package.
namespace Controllers
{
using Services;
using DataTransferObjects;
public class CoffeeController
{
public ICoffeeService CoffeeService { get; set; }
public JsonResult GetCoffee(GetCoffeeInDto inDto)
{
var result = CoffeeService.GetCoffee(inDto);
return JsonResult(result);
}
public JsonResult SaveCoffee(SaveCoffeeInDto inDto)
{
var outDto = CoffeeService.SaveCoffee(inDto);
return JsonResult(outDto);
}
}
}
namespace Services
{
using DataTransferObjects;
public interface ICoffeeService
{
GetCoffeeOutDto GetCoffee(GetCoffeeInDto inDto);
SaveCoffeeOutDto SaveCoffee(SaveCoffeeInDto inDto);
}
}
namespace Services.Impl
{
using Services;
using Repository;
using DataTransferObjects;
using Domain;
public class CoffeeService : ICoffeeService
{
public ICoffeeRepository CoffeeRepository { get; set; }
public GetCoffeeOutDto GetCoffee(GetCoffeeInDto inDto)
{
var entity = CoffeeRepository.Get(inDto.Id);
return new GetCoffeeOutDto {Id = entity.Id, Name = entity.Name};
}
public SaveCoffeeOutDto SaveCoffee(SaveCoffeeInDto inDto)
{
var entity = new CoffeeEntity {Name = inDto.Name};
CoffeeRepository.Save(entity);
return new SaveCoffeeOutDto {Id = entity.Id};
}
}
}
namespace Repository
{
using Domain;
public interface ICoffeeRepository
{
CoffeeEntity Get(int id);
void Save(CoffeeEntity coffeeEntity);
}
}
namespace Repository.Impl
{
using Repository;
using Domain;
public class CoffeeRepository:ICoffeeRepository
{
public CoffeeEntity Get(int id)
{
//get entity from db
throw new System.NotImplementedException();
}
public void Save(CoffeeEntity coffeeEntity)
{
//insert entity into db
throw new System.NotImplementedException();
}
}
}
namespace DataTransferObjects
{
public class SaveCoffeeInDto
{
public string Name { get; set; }
}
public class SaveCoffeeOutDto
{
public int Id { get; set; }
}
public class GetCoffeeInDto
{
public int Id { get; set; }
}
public class GetCoffeeOutDto
{
public int Id { get; set; }
public string Name { get; set; }
}
}
namespace Domain
{
public class CoffeeEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
}
I'm working on an application which uses Automapper, Unit Of Work, Entity Framework 5, ASPNET MVC 4, WebApi and Windsor Castle from Nuget.
I'm not sure if I should map this or it should be mapped by Automapper automatically
public IEnumerable<StoreDto> Get()
{
return Uow.Stores.GetAll().OrderBy(s => s.Name);
}
Uow.Stores.GetAll().OrderBy(s => s.Name) returns an IOrderedQueryable<Store>.
I'm receiving the error message
Cannot convert expresion type IOrderedQueryable to type IEnumerable
Should I do a foreach and convert each object returned by GetAll to StoreDto with Mapper.Map method of Automapper? Wouldn't Automapper convert it for me?
This is how I'm using Automapper and how I'm registering it. Please let me know if something should/can be improved.
AutomapperInstaller.cs:
public class AutoMapperInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
Mapper.Initialize(x => x.ConstructServicesUsing(container.Resolve));
RegisterProfilesAndResolvers(container);
RegisterMapperEngine(container);
}
private void RegisterMapperEngine(IWindsorContainer container)
{
container.Register(Component.For<IMappingEngine>().Instance(Mapper.Engine));
}
private void RegisterProfilesAndResolvers(IWindsorContainer container)
{
// register value resolvers
container.Register(AllTypes.FromAssembly(Assembly.GetExecutingAssembly()).BasedOn<IValueResolver>());
// register profiles
container.Register(AllTypes.FromThisAssembly().BasedOn<Profile>());
var profiles = container.ResolveAll<Profile>();
foreach (var profile in profiles)
{
Mapper.AddProfile(profile);
}
}
WebWindsorInstaller:
internal class WebWindsorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component
.For<RepositoryFactories>()
.ImplementedBy<RepositoryFactories>()
.LifestyleSingleton());
container.Register(Component
.For<IRepositoryProvider>()
.ImplementedBy<RepositoryProvider>()
.LifestylePerWebRequest());
container.Register(Component
.For<IProjUow>()
.ImplementedBy<ProjUow>()
.LifestylePerWebRequest());
container.Register(Classes
.FromAssemblyContaining<Api.StoresController>()
.BasedOn<IHttpController>()
.If(t => t.Name.EndsWith("Controller"))
.LifestylePerWebRequest());
RegisterMapping(container, store);
}
private void RegisterMapping(IWindsorContainer container, IConfigurationStore store)
{
Mapper.CreateMap<Store, StoreDto>();
}
}
Store.cs:
public class Store
{
public Store()
{
this.Branches = new List<Branch>();
}
public int Id { get; set; }
public string Name { get; set; }
public System.Data.Spatial.DbGeography Location{ get; set; }
public virtual ICollection<Branch> Branches{ get; set; }
}
StoreDto.cs (same as Store by now)
public class StoreDto
{
public StoreDto()
{
this.Branches = new List<BranchDto>();
}
public int Id { get; set; }
public string Name { get; set; }
public System.Data.Spatial.DbGeography Location{ get; set; }
public virtual ICollection<BranchDto> Branches{ get; set; }
}
And this is how I'm calling the installer in IocConfig.cs:
Container = new WindsorContainer()
.Install(new AutoMapperInstaller())
.Install(new ControllersInstaller());
I'm not sure if I should include there
.AddFacility<FactorySupportFacility>()