I know there is get and post method in razor page but what if you want you load some code soon as page is loads up? do I use a constructor method?
public async Task<IActionResult> OnGetAsync()
{
return Page();
}
public async Task<IActionResult> OnPostAsync(){
return Page();
}
Do you mean you want to use depedency injection?If so,you can try to use a constructor method.Firstly,you need to register a service in Program.cs,and then use a constructor in your pagemodel.
ICommentService:
public interface ICommentService
{
string Test();
}
CommentService:
public class CommentService : ICommentService
{
public string Test()
{
return "Test";
}
}
pageModel:
public class TestdModel : PageModel
{
private readonly ICommentService _commentService;
public TestdModel (ICommentService commentService)
{
_commentService = commentService;
}
}
Then you can use _commentService in your pagemodel.
Related
hello guys I have problem with this error. my project is simple I have an Interface called "IApiService" and I have a class called Api that is relative with my IApiService Interface. So in "Api" I have a method that post an api and I think this error doesn't relative with my error. I think error is in my Controller. So I will put my controller code so you guys could help me with!
Here it is:
public class HomeController : Controller
{
IApiService _apiService;
public HomeController(IApiService apiService)
{
_apiService = apiService;
}
// GET: Home
public async Task<ActionResult> Index(CheckOutViewModel model)
{
var result = await _apiService.CheckOut(model);
return View();
}
}
For asp.net framework:
The difference is that you should have your controller like this, no need to inject dependency:
public class HomeController : Controller
{
IApiService _apiService;
public HomeController() : this(new ApiService())
{
}
public HomeController(IApiService apiService)
{
_apiService = apiService;
}
public string getString(string name) {
string a = _apiService.CheckOut(name);
return a;
}
}
==============================================
Please allow me to show a sample here, asp.net core.
My Controller:
public class HomeController : Controller
{
private readonly IApiService _apiService;
public HomeController( IApiService iapiService)
{
_apiService = iapiService;
}
public string getString(string name) {
string a = _apiService.CheckOut(name);
return a;
}
}
My interface:
namespace WebMvcApp.Services
{
public interface IApiService
{
public string CheckOut(string str);
}
}
My implement of the interface:
namespace WebMvcApp.Services
{
public class ApiService: IApiService
{
public string CheckOut(string str)
{
return "hello : " + str;
}
}
}
I inject the dependency in startup.cs -> ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddScoped<IApiService, ApiService>();
}
or in .net 6 in Program.cs file:
builder.Services.AddControllersWithViews();
builder.Services.AddScoped<IApiService, ApiService>();
I am using an ORM to connect to the database it is called dapper. The issue with it is that it's database calls are synchronous and I recently found a way to make it asynchronous by following this short tutorial http://www.joesauve.com/async-dapper-and-async-sql-connection-management/ . My question is how can I bring this BaseRepository into my Controller class ? This is the code on that website and it's the same one I have
BaseRepository- by the way there is no issue in this code
public abstract class BaseRepository
{
private readonly string _ConnectionString;
protected BaseRepository(string connectionString)
{
_ConnectionString = connectionString;
}
protected async Task<T> WithConnection<T>(Func<IDbConnection, Task<T>> getData)
{
try {
using (var connection = new SqlConnection(_ConnectionString)) {
await connection.OpenAsync(); // Asynchronously open a connection to the database
return await getData(connection); // Asynchronously execute getData, which has been passed in as a Func<IDBConnection, Task<T>>
}
}
catch (TimeoutException ex) {
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL timeout", GetType().FullName), ex);
}
catch (SqlException ex) {
throw new Exception(String.Format("{0}.WithConnection() experienced a SQL exception (not a timeout)", GetType().FullName), ex);
}
}
}
and now he brings it in like this
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}
The part I am having a problem with is this public class PersonRepository : BaseRepository because Asp.Net Controllers start with public class HomeController: Controller , I need access to the WithConnection method to get this working. My controller looks like this
public class HomeController : Controller
{
public class ConnectionRepository : BaseRepository
{
public ConnectionRepository(string connectionString) : base(connectionString) { }
}
public async Task<ActionResult> topfive()
{
// I get Error on WithConnection as it can't see the BaseRepository
return await WithConnection(async c =>
{
var topfive = await c.QueryAsync<Streams>("select * from streams ").ToList();
return View(topfive);
});
}
}
I obviously can not cover my ActionResult method with the BaseRepository because it gives all types of errors any suggestions ?
Why are you using inheritance instead of composition? What about something like:
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}
public class ConnectionRepository : BaseRepository
{
public ConnectionRepository(string connectionString) : base(connectionString) { }
}
public async Task<List<TopFileClass>> topfive()
{
// I get Error on WithConnection as it can't see the BaseRepository
return await WithConnection(async c =>
{
var topfive = await c.QueryAsync<Streams>("select * from streams ").ToList();
return topfive;
});
}
public class HomeController : Controller
{
private readonly PersonRepository _repo;
public HomeController(PersonRepository repo)
{
_repo = repo;
}
public async Task<ActionResult> TopFive()
{
var top5 = await _repo.topfive();
return View(top5);
}
}
If you are not familiar how to make the repository automatically get injected into the constructor, read up on dependency injection in MVC 6.
you have to intehirt the "BaseRepository" from "Controller". i think that will work for you. then just go with below code:
public abstract class BaseRepository : Controller
{
// do you work
}
public class PersonRepository : BaseRepository
{
public PersonRepository(string connectionString): base (connectionString) { }
public async Task<Person> GetPersonById(Guid Id)
{
return await WithConnection(async c => {
// Here's all the same data access code,
// albeit now it's async, and nicely wrapped
// in this handy WithConnection() call.
var p = new DynamicParameters();
p.Add("Id", Id, DbType.Guid);
var people = await c.QueryAsync<Person>(
sql: "sp_Person_GetById",
param: p,
commandType: CommandType.StoredProcedure);
return people.FirstOrDefault();
});
}
}
The old controller code with Concrete dependencies:
public SomeController: Controller
{
public SomeController()
{
}
public ActionResult Default()
{
**Something something = new Something(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString());**
something.SomeMethod();
}
}
The new Controller code with TDD focus:
public SomeControllerNew: Controller
{
private readonly ISomething _something;
public SomeControllerNew(ISomething something)
{
_something = something;
}
public ActionResult Default()
{
_something.SomeMethod();
}
}
PROBLEM:
Now in new TDD approach i need to invoke constructor where I am registering the Interface. I have put it in UnityBootstraper common file, Something like:
var container = new UnityContainer();
container.RegisterType();
**Something something = new Something(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString());**
something.SomeMethod();
This is not working here. Error is quite clear:
Object reference required for non-static field, method, property 'System.Web.Mvc.Controller.Request.get'.
I can't figure out how i can access http request here in UnityBootstrapper?
Edit:
Trying to do all this in RegisterRoutes.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
DependencyResolver.SetResolver(new Unity.Mvc3.UnityDependencyResolver(UnityBootstrapper.Initialise()));
var container = new UnityContainer();
container.RegisterType<ISometing, Something>();
}
}
One way to do it is to create an abstract factory like this:
public interface ISomethingFactory
{
ISomething Create(string url);
}
public class SomethingFactory : ISomethingFactory
{
public ISomething Create(string url)
{
return new Something(url);
}
}
And make your controller depend on it like this:
public class SomeControllerNew: Controller
{
private readonly ISomething _something;
public SomeControllerNew(ISomethingFactory somethingFactory)
{
_something = somethingFactory.Create(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString();
}
public ActionResult Default()
{
_something.SomeMethod();
}
}
A better approach (IMO) is to use a custom Controller Factory instead of using the Dependency Resolver like this:
public class CustomFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var request = requestContext.HttpContext.Request; //Here we have access to the request
if (controllerName == "Some") //Name of controller
{
//Use the container to resolve and return the controller.
//When you resolve, you can use ParameterOverride to specify the value of the string dependency that you need to inject into Something
}
return base.CreateController(requestContext, controllerName);
}
}
This way you don't have to introduce the ISomethingFactory, and your controller would still depend on ISomething directly.
You would need to tell the MVC framework about this custom controller factory like this (in Application_Start):
ControllerBuilder.Current.SetControllerFactory(new CustomFactory());
PLEASE: If my question isn't clear, please tell me and I'll try to rephrase it
I need [Default Constructor] in LogOnModel, so it can't be removed.
LoadModel+ModelFactory and LogOnModel are physically in different files in different projects AND project2 has reference to project1 and NOT vice versa.
1 - Let say that
type=typeof(LogOnModel). When ObjectFactory.GetInstance(t) is called I want it to call the
parameterized constructor of LogOnModel and pass it the #params
2 - If I'll add to the parameterized constructor of LogOnModel another parameter,for example
public LogOnModel(string param, IPageService pageService)
so ObjectFacytory should call this constructor without any problems
How to configure/initiate ObjectFactory, so this will work?
Thank you
EDITED
//Project1/file1.cs
public void LoadModel(Type type, string param)
{
var factory = new ModelFactory();
var model = factory.Get(type, **param**);
}
public class ModelFactory : IModelFactory
{
public PageModel Get(Type t, **string param**)
{
//NOW I NEED SOMEHOW TO PASS **param** TO EVERY INSTANCE THAT INHERITS FROM **PageModel**
return ObjectFactory.GetInstance(t) as PageModel;
}
}
//Project2/file2.cs
public class LogOnModel : PageModel
{
public LogOnModel()
{
}
public LogOnModel(string param)
{
}
}
public class Model2 : PageModel
{
public LogOnModel()
{
}
public LogOnModel(string param)
{
}
}
public class Model3 : PageModel
{
public LogOnModel()
{
}
public LogOnModel(string param)
{
}
}
StructureMap will use the constructor with the most parameters by default, so that part is easy. Then you just need to configure the value of param like so:
ObjectFactory.Initialize(i => {
i.For<LogOnModel>().Use<LogOnModel>();
});
When you call the container, use the with method to pass in your parameter:
return ObjectFactory.With("param").EqualTo(param).GetInstance(t) as PageModel;
I'm using a configuration within the global.asax.cs to register the components but it looks the container hasn't been initialized yet at the first http request (HomeController > Index action) and it gives me a "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection." error.
I can't find a solution for this and is driving me mad!
Extract of my global.asax.cs:
protected void Application_Start()
{
InitializeContainer();
InitializeDatabase();
RegisterRoutes(RouteTable.Routes);
}
private void InitializeContainer()
{
_container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_container));
// Register context manager.
_container.Register(
Component.For<IContextManager>()
.ImplementedBy<CoursesContextManager>()
.LifeStyle.Singleton
.Parameters(
Parameter.ForKey("connectionString").Eq(ConfigurationManager.ConnectionStrings["CoursesConnection"].ConnectionString)
)
);
// Register specifc repository implementations (can we do this more generic?)
_container.Register(
Component.For<ICourseRepository>()
.ImplementedBy<CourseRepository>()
.LifeStyle.Singleton
);
[...other interfaces and controllers registered...]
}
Controller where the exception is thrown at first http request:
public class HomeController : Controller
{
private ICourseRepository _courseRepository;
public HomeController(ICourseRepository courseRepository)
{
_courseRepository = courseRepository;
}
public ActionResult Index()
{
var courses = _courseRepository.Find(); //here is where it fails
return View(courses);
}
}
Repository/interfaces:
Generic interface:
public interface IRepository<T>
{
IQueryable<T> Find();
}
Generic repository:
public class MyRepository<T> : IRepository<T> where T : class
{
private IContextManager _contextManager;
private string _qualifiedEntitySetName;
private string _keyName;
protected ObjectContext CurrentObjectContext
{
get { return _contextManager.GetContext(); }
}
protected ObjectSet<T> ObjectSet
{
get { return CurrentObjectContext.CreateObjectSet<T>(); }
}
public MyRepository(IContextManager contextManager)
{
this._contextManager = contextManager;
this._qualifiedEntitySetName = string.Format("{0}.{1}"
, this.ObjectSet.EntitySet.EntityContainer.Name
, this.ObjectSet.EntitySet.Name);
this._keyName = this.ObjectSet.EntitySet.ElementType.KeyMembers.Single().Name;
}
public IQueryable<T> Find()
{
return ObjectSet;
}
}
Interface course based on generic repository:
public interface ICourseRepository : IRepository<Course>
{
}
if you use Unit Of Work pattern you will solve your problem
Check this post Unit Of Work Pattern, is very usefull
I found a way to handle with this at least momentarily. Because the problem happens on the first request, I've just added another action in my controller and redirect the index action to it. Probably not the best solution but can't spend more time on this issue!
public class HomeController : Controller
{
private ICourseRepository _courseRepository;
public HomeController(ICourseRepository courseRepository)
{
_courseRepository = courseRepository;
}
public ActionResult Index() // Default action in the controller, first hit
{
return RedirectToAction("Home");
}
public ActionResult Home() //The repository is available here, no exception thrown
{
var courses = _courseRepository.Find(); //here is where it fails
return View(courses);
}
}