Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. WPF
  4. WPF EF Core 6 DP Question

WPF EF Core 6 DP Question

Scheduled Pinned Locked Moved WPF
questioncsharpasp-netwpfsecurity
6 Posts 2 Posters 7 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    Kevin Marois
    wrote on last edited by
    #1

    I'm working on an app that has two repository projects. The first is part of my framework and is called ApplicationSecurity. It has Users, Rights, Encryption, etc. It's designed to be generic and used in any app. It expects an instance of an EF DBContext to be passed into the CTOR The second repo project is for my app itself. Its tables are app specific. The DBContext resides in this project So, I build the DBContext in this second project, and used it in both. In my App.cs CTOR I have:

    public App()
    {
    AppHost = Host.CreateDefaultBuilder()
    .ConfigureServices((hostContext, services) =>
    {
    services.AddSingleton();
    services.AddSingleton();
    services.AddSingleton();
    services.AddSingleton();
    services.AddSingleton();
    services.AddSingleton();
    })
    .Build();
    }

    How do I include my DBContext here? [ ] My ApplicationSecurity class needs an instance of the DBContext class. How can I pass a reference to a DBContext into the ApplicationSecurity CTOR?

    In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.

    Richard DeemingR 1 Reply Last reply
    0
    • K Kevin Marois

      I'm working on an app that has two repository projects. The first is part of my framework and is called ApplicationSecurity. It has Users, Rights, Encryption, etc. It's designed to be generic and used in any app. It expects an instance of an EF DBContext to be passed into the CTOR The second repo project is for my app itself. Its tables are app specific. The DBContext resides in this project So, I build the DBContext in this second project, and used it in both. In my App.cs CTOR I have:

      public App()
      {
      AppHost = Host.CreateDefaultBuilder()
      .ConfigureServices((hostContext, services) =>
      {
      services.AddSingleton();
      services.AddSingleton();
      services.AddSingleton();
      services.AddSingleton();
      services.AddSingleton();
      services.AddSingleton();
      })
      .Build();
      }

      How do I include my DBContext here? [ ] My ApplicationSecurity class needs an instance of the DBContext class. How can I pass a reference to a DBContext into the ApplicationSecurity CTOR?

      In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.

      Richard DeemingR Offline
      Richard DeemingR Offline
      Richard Deeming
      wrote on last edited by
      #2

      Either services.AddDbContext<TContext>(...)[^], or services.AddDbContextPool<TContext>(...)[^] - as per the remarks, pooling probably won't add much benefit for most small applications.


      "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

      "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

      K 1 Reply Last reply
      0
      • Richard DeemingR Richard Deeming

        Either services.AddDbContext<TContext>(...)[^], or services.AddDbContextPool<TContext>(...)[^] - as per the remarks, pooling probably won't add much benefit for most small applications.


        "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

        K Offline
        K Offline
        Kevin Marois
        wrote on last edited by
        #3

        OK, so I now have

        AppHost = Host.CreateDefaultBuilder()
        .ConfigureServices((hostContext, services) =>
        {
        services.AddDbContext(options =>
        {
        options.UseSqlServer(_connString);
        });

                        services.AddSingleton();
                        services.AddSingleton();
                        services.AddSingleton();
                        services.AddSingleton();
                        services.AddSingleton();
                        services.AddSingleton();
                    })
                    .Build();
        

        }

        But the ApplicationSecurity class needs an instance of MyDbContext. How do I pass that in?

        In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.

        Richard DeemingR 1 Reply Last reply
        0
        • K Kevin Marois

          OK, so I now have

          AppHost = Host.CreateDefaultBuilder()
          .ConfigureServices((hostContext, services) =>
          {
          services.AddDbContext(options =>
          {
          options.UseSqlServer(_connString);
          });

                          services.AddSingleton();
                          services.AddSingleton();
                          services.AddSingleton();
                          services.AddSingleton();
                          services.AddSingleton();
                          services.AddSingleton();
                      })
                      .Build();
          

          }

          But the ApplicationSecurity class needs an instance of MyDbContext. How do I pass that in?

          In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.

          Richard DeemingR Offline
          Richard DeemingR Offline
          Richard Deeming
          wrote on last edited by
          #4

          Add it as a constructor parameter. Or are you saying that the ApplicationSecurity is defined in an assembly which doesn't have a reference to the assembly where the MooseDBContext is defined? If that's the case, then you probably want the context to implement an interface:

          // ApplicationSecurity assembly:
          public interface IApplicationSecurityContext
          {
          DbSet<YourEntityType> YourEntityTypes { get; }
          }

          public class ApplicationSecurity : IApplicationSecurity
          {
          public ApplicationSecurity(IApplicationSecurityContext context)
          {
          ArgumentNullException.ThrowIfNull(context);
          Context = context;
          }

          private IApplicationSecurityContext Context { get; }
          ...
          

          }

          // MooseDBContext assembly:
          public class MooseDBContext : DbContext, IApplicationSecurityContext
          {
          ...
          }

          Then register the interfaces as services:

          services.AddDbContext(options =>
          {
          options.UseSqlServer(_connString);
          });

          // When we request the IApplicationSecurityContext service,
          // return the registered MooseDBContext service:
          services.AddScoped(sp => sp.GetRequiredService());

          You could even create a utility method to automatically register all interfaces implemented by your context:

          public static IServiceCollection AddContextInterfaces(this IServiceCollection services) where TContext : DbContext
          {
          ArgumentNullException.ThrowIfNull(services);

          foreach (Type t in typeof(TContext).GetInterfaces().Except(typeof(DbContext).GetInterfaces()))
          {
              services.AddScoped(t, sp => sp.GetRequiredService());
          }
          
          return services;
          

          }

          ...

          services.AddDbContext(options =>
          {
          options.UseSqlServer(_connString);
          });

          services.AddContextInterfaces();


          "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

          "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

          K 1 Reply Last reply
          0
          • Richard DeemingR Richard Deeming

            Add it as a constructor parameter. Or are you saying that the ApplicationSecurity is defined in an assembly which doesn't have a reference to the assembly where the MooseDBContext is defined? If that's the case, then you probably want the context to implement an interface:

            // ApplicationSecurity assembly:
            public interface IApplicationSecurityContext
            {
            DbSet<YourEntityType> YourEntityTypes { get; }
            }

            public class ApplicationSecurity : IApplicationSecurity
            {
            public ApplicationSecurity(IApplicationSecurityContext context)
            {
            ArgumentNullException.ThrowIfNull(context);
            Context = context;
            }

            private IApplicationSecurityContext Context { get; }
            ...
            

            }

            // MooseDBContext assembly:
            public class MooseDBContext : DbContext, IApplicationSecurityContext
            {
            ...
            }

            Then register the interfaces as services:

            services.AddDbContext(options =>
            {
            options.UseSqlServer(_connString);
            });

            // When we request the IApplicationSecurityContext service,
            // return the registered MooseDBContext service:
            services.AddScoped(sp => sp.GetRequiredService());

            You could even create a utility method to automatically register all interfaces implemented by your context:

            public static IServiceCollection AddContextInterfaces(this IServiceCollection services) where TContext : DbContext
            {
            ArgumentNullException.ThrowIfNull(services);

            foreach (Type t in typeof(TContext).GetInterfaces().Except(typeof(DbContext).GetInterfaces()))
            {
                services.AddScoped(t, sp => sp.GetRequiredService());
            }
            
            return services;
            

            }

            ...

            services.AddDbContext(options =>
            {
            options.UseSqlServer(_connString);
            });

            services.AddContextInterfaces();


            "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

            K Offline
            K Offline
            Kevin Marois
            wrote on last edited by
            #5

            Thanks, that seems to work fine. My class now looks like this:

            using Marois.Framework.Core.AppSecurity.Repository;
            using Marois.Framework.Core.Crypto;
            using Marois.Framework.Core.Shared;
            using Microsoft.EntityFrameworkCore;

            namespace Marois.Framework.Core.AppSecurity.Service
            {
            public class ApplicationSecurity : IApplicationSecurity
            {
            #region Private Fields
            private IApplicationSecurityContext _context { get; }
            #endregion

                #region CTOR
                public ApplicationSecurity(IApplicationSecurityContext context)
                {
                    ArgumentNullException.ThrowIfNull(nameof(context));
            
                    \_context = context;
                }
                #endregion
            
                #region Public Methods
                public Task LoginAsync(CredentialsEntity credentials)
                {
                    UserEntity? results = null;
            
                    ArgumentNullException.ThrowIfNull(nameof(credentials));
            
                    var t = Task.Run(() =>
                    {
                        var userRepo = new AppSecurityRepository((DbContext)\_context);
            
                        var user = userRepo.Find(x => x.UserName == credentials.UserName);
            
                        if (Cryptography.VerifyHash(credentials.Password, user.Password, user.Hash))
                        {
                            results = user;
                        }
            
                        return results;
                    });
            
                    return t;
                }
                #endregion
            }
            

            }

            In the Login method, would you create an instance of the repo, or create it in the CTOR and persist it?

            In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.

            Richard DeemingR 1 Reply Last reply
            0
            • K Kevin Marois

              Thanks, that seems to work fine. My class now looks like this:

              using Marois.Framework.Core.AppSecurity.Repository;
              using Marois.Framework.Core.Crypto;
              using Marois.Framework.Core.Shared;
              using Microsoft.EntityFrameworkCore;

              namespace Marois.Framework.Core.AppSecurity.Service
              {
              public class ApplicationSecurity : IApplicationSecurity
              {
              #region Private Fields
              private IApplicationSecurityContext _context { get; }
              #endregion

                  #region CTOR
                  public ApplicationSecurity(IApplicationSecurityContext context)
                  {
                      ArgumentNullException.ThrowIfNull(nameof(context));
              
                      \_context = context;
                  }
                  #endregion
              
                  #region Public Methods
                  public Task LoginAsync(CredentialsEntity credentials)
                  {
                      UserEntity? results = null;
              
                      ArgumentNullException.ThrowIfNull(nameof(credentials));
              
                      var t = Task.Run(() =>
                      {
                          var userRepo = new AppSecurityRepository((DbContext)\_context);
              
                          var user = userRepo.Find(x => x.UserName == credentials.UserName);
              
                          if (Cryptography.VerifyHash(credentials.Password, user.Password, user.Hash))
                          {
                              results = user;
                          }
              
                          return results;
                      });
              
                      return t;
                  }
                  #endregion
              }
              

              }

              In the Login method, would you create an instance of the repo, or create it in the CTOR and persist it?

              In theory, theory and practice are the same. But in practice, they never are.” If it's not broken, fix it until it is. Everything makes sense in someone's mind.

              Richard DeemingR Offline
              Richard DeemingR Offline
              Richard Deeming
              wrote on last edited by
              #6

              It's a dependency, so I'd be inclined to inject the repo rather than the context. :) NB: Entity Framework supports asynchronous database queries, so it would be better to offer a FindAsync method on the repo, and get rid of the Task.Run call.

              public class ApplicationSecurity : IApplicationSecurity
              {
              private AppSecurityRepository _userRepo { get; }

              public ApplicationSecurity(AppSecurityRepository userRepo)
              {
                  ArgumentNullException.ThrowIfNull(nameof(userRepo));
                  \_userRepo = userRepo;
              }
              
              public async Task LoginAsync(CredentialsEntity credentials)
              {
                  var user = await \_userRepo.FindAsync(x => x.UserName == credentials.UserName);
                  if (user is null) return null;
                  
                  return Cryptography.VerifyHash(credentials.Password, user.Password, user.Hash) ? user : null;
              }
              

              }

              NB2: Why does your user entity have both a Password and a Hash property? I'd expect to see a "protected password" property, and possibly a "salt" property, depending on whether the salt is stored as a separate column or combined with the password hash.


              "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

              "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • World
              • Users
              • Groups