Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 days ago.
Improve this question
I'm trying to use maui with blazor and I'm having problems with dependency injection.
I created a class library to contain services, repositories and entities and did something like this:
public abstract class ApplicationDbContext
{
public ApplicationDbContext(){}
public async Task<SQLiteAsyncConnection> Init<T>() where T : class, new()
{
var database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags);
var result = await database.CreateTableAsync<T>();
return database;
}
}
public interface IRepository<TEntity> where TEntity : class, new()
{
Task<List<TEntity>> GetAllAsync();
}
public class BaseRepository<TEntity> : ApplicationDbContext, IRepository<TEntity> where TEntity : class, new()
{
public BaseRepository() { }
public async Task<List<TEntity>> GetAllAsync()
{
var dataBase = await base.Init<TEntity>();
return await dataBase.Table<TEntity>().ToListAsync();
}
}
I created a page called Register.razor and a class Register.razor.cs.
I can't inject the repository. always gives an error when I put it in the construtor.
I can't catch the error. Clicking on the menu displays a generic error about not being able to open the page. But if I remove the repository from the constructor, it does not generate an error
Related
I have an Asp.Net Core 3.1 Razor Pages website in which I have a static Repository class holding the most used items. I search these items a lot and it takes around 4 minutes to initialize them.
public static class Repository
{
public static Dictionary<int, RepositoryPerson> People { get; private set; }
public static async Task InitAsync(INoSqlSettings settings)
{
if (People != null || loading)
{
return;
}
loading = true;
var people = await db.People.ToDictionaryAsync(p => p.Id);
People = ConvertToRepository(people);
//..and lots of other stuff
loading = false;
}
}
At first, I tried to load this with a hosted service but it fails because it takes too long. Now I load it in the Index.cshtml.cs file's OnGetAsync(). But the problem is that every once in awhile, it seems like the .exe file closes because the website initializes again. Is this normal? How can I make the program run only once and share the in-memory repository forever?
Why have you declared the class as static? The common way, as described in the docs, is to use Dependency Injection mechanism of ASP.Net Core.
You can implement it by registering your instance of your class as a Singleton in your Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
//...
var myRepo = new Repository();
repo.InitAsync(someSettings); //Not async now
services.AddSingleton<Repository>(myRepo);
//...
}
Afterwards retrieve the Instance with Dependency Injection, like this:
public class MyPageModel : PageModel
{
private readonly Repository _repo;
public MyPageModel(Repository repo)
{
_repo = repo;
}
See docs for Razor page dependency injection.
When i try to run the project, i am getting this kind of error: "System.NullReferenceException: Object reference not set to an instance of an object"
pointing in this code:
sqliteconnection = DependencyService.Get().GetConnection();
This is my Class for DB actions:
namespace DevoApp.DevoAppFinal.Helpers
{
public class DatabaseHelper
{
static SQLiteConnection sqliteconnection;
public const string DbFileName = "Devotion.db";
public DatabaseHelper()
{
sqliteconnection = DependencyService.Get<ISQLite>().GetConnection();
sqliteconnection.CreateTable<Devotion>();
}
// Get All Contact data
public List<Devotion> GetAllDevotionsData()
{
return (from data in sqliteconnection.Table<Devotion>() select data).ToList();
}
//Get Specific Contact data
public Devotion GetDevotionData(int id)
{
return sqliteconnection.Table<Devotion>().FirstOrDefault(t => t.devotionalId == id);
}
// Delete all Contacts Data
public void DeleteAllDevotions()
{
sqliteconnection.DeleteAll<Devotion>();
}
// Delete Specific Contact
public void DeleteDevotion(int id)
{
sqliteconnection.Delete<Devotion>(id);
}
// Insert new Contact to DB
public void InsertDevotion(Devotion contact)
{
sqliteconnection.Insert(contact);
}
// Update Contact Data
public void UpdateDevotion(Devotion contact)
{
sqliteconnection.Update(contact);
}
}
}
When using the DependencyService, you have to implement the interface in each targeted platform project.
In this case, you should have the ISQLite interface implemented on the platforms you're targeting, i.e. iOS and Android.
To make Xamarin find it at runtime, you will have to register the implementation with the Dependency attribute above the namespace. Observe the following example based on a few assumptions of your project.
In your shared library you have declared the interface:
public interface ISQLite
{
// Members here
}
Nothing fancy going on there. Then for each platform, you want to run the app on, do something like this:
[assembly: Xamarin.Forms.Dependency (typeof (SQLiteImplementation_iOS))]
namespace DevoApp.DevoAppFinal.iOS
{
public class SQLiteImplementation_iOS : ISQLite
{
// ... Your code
}
}
From the error, it looks like you forgot to add the attribute
This question already has answers here:
Inject service into Action Filter
(6 answers)
Closed 6 years ago.
I am writing attribute that will verify captcha. In order to work correctly it needs to know secret, which I keep in the settings (Secret manager tool). However I don't know how to read config from the attribute class. DI in asp.net core supports constructor injection (and property injection is not supported), so this will give compilation error:
public ValidateReCaptchaAttribute(IConfiguration configuration)
{
if (configuration == null)
{
throw new ArgumentNullException("configuration");
}
this.m_configuration = configuration;
}
because when I decorate method with [ValidateReCaptcha] I can't pass config
So how do I can read something from config from the method in attribute class?
You can use ServiceFilter attribute, more info in this blog post and asp.net docs.
[ServiceFilter(typeof(ValidateReCaptchaAttribute))]
public IActionResult SomeAction()
In Startup
public void ConfigureServices(IServiceCollection services)
{
// Add functionality to inject IOptions<T>
services.AddOptions();
// Add our Config object so it can be injected
services.Configure<CaptchaSettings>(Configuration.GetSection("CaptchaSettings"));
services.AddScoped<ValidateReCaptchaAttribute>();
...
}
And ValidateReCaptchaAttribute
public class ValidateReCaptchaAttribute : ActionFilterAttribute
{
private readonly CaptchaSettings _settings;
public ValidateReCaptchaAttribute(IOptions<CaptchaSettings> options)
{
_settings = options.Value;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
...
base.OnActionExecuting(context);
}
}
You should use ServiceFilter like this:
[ServiceFilter(typeof(ValidateReCaptcha))]
And if you want to use IConfiguration you should inject it in ConfigureServices:
services.AddSingleton((provider)=>
{
return Configuration;
});
I've created a gist highlighting the issue I'm running into. I'm using an Application Module to provide a Firebase dependency for me to inject elsewhere.
When I try to #Inject Firebase mFirebase in the data layer that dependency is never satisfied.
I'm trying to keep the Context out of my other layers, but the Firebase service depends on it. I'm interested in learning any other patterns to help keep Android classes out of my business logic.
FirebaseService.java
public class FirebaseService {
#Inject Firebase mFirebaseRef; //NEVER GET'S INJECTED!
#Override
public LoginResult signinWithEmail(final String email, final String password) {
mFirebaseRef.dostuff(); //THIS REFERENCE DOESN'T GET INJECTED!
}
}
ApplicationModule
#Provides
#Singleton
Firebase provideFirebase(#ApplicationContext Context context) {
Firebase.setAndroidContext(context);
return new Firebase(Util.FIREBASE_URL);
}
ApplicationComponent
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
#ApplicationContext Context context();
Application application();
Firebase firebase();
}
MyActivity
public class MyActivity extends AppCompatActivity {
private ActivityComponent mActivityComponent;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public ActivityComponent getActivityComponent() {
if (mActivityComponent == null) {
mActivityComponent = DaggerActivityComponent.builder()
.activityModule(new ActivityModule(this))
.applicationComponent(MyApplication.get(this).getComponent())
.build();
}
return mActivityComponent;
}
The full code example is on github
Annotating a field with #Inject is not enough for the field injection to work. There's no magic involved, you just have to tell Dagger to do the injection.
First, add this method to your ApplicationComponent:
void inject(FirebaseService firebaseService);
Then, call this method from your FirebaseService (I guess it's an Android service, so add this to the onCreate method):
applicationComponent.inject(this);
This should do the trick. There's a great answer to a similar problem here.
EDIT
I've looked at your repository and I think you don't even need field injection in this case. You can just provide the Firebase dependency through a constructor. Here's your #Provides method:
#Provides
#Singleton
LoginService provideLoginService() {
return new FirebaseLoginService();
}
Add Firebase as a parameter to it and pass it to the FirebaseLoginService constructor:
#Provides
#Singleton
LoginService provideLoginService(Firebase firebase) {
return new FirebaseLoginService(firebase);
}
The constructor:
public FirebaseLoginService(Firebase firebase) {
this.mFirebaseRef = firebase;
}
Remove the #Inject annotation from your mFirebaseRef field since it's not needed anymore.
Here's the corresponding pull request.
On an ASP.NET MVC solution I have a Service layer which contains services for each Model. For example for DocumentModel I have Document Service which is instantiated by a UoW class which acts like a factory and does the save:
public class UnitOfWork : IUnitOfWork
{
private IRepositoryFactory _repositoryFactory;
public UnitOfWork()
: this(new RepositoryFactory())
{
}
public UnitOfWork(IRepositoryFactory repositoryFactory)
{
_repositoryFactory = repositoryFactory;
}
private IDocumentService _DocumentService;
public IDocumentService DocumentService
{
get
{
if (_DocumentService == null)
{
_DocumentService = new DocumentService(_repositoryFactory.DocumentRepository);
}
return _DocumentService;
}
}
}
Now say I need to be able to access 2 or 3 other repositories from DocumentService. What is the best way to inject this new repositories? Add them in the constructor( which if I need to add yet another repository can become cumbersome) or should I just inject the repository factory (IRepositoryFactory) which will allow me to access in DocumentService any repository I may need.