2016-10-09 5 views
0

В настоящее время я настраиваю веб-приложение .net и настраиваю MailKit для обработки его отправки по электронной почте.Невозможно получить секрет пользователя от менеджера Confiuration в .net core

Вместо того, чтобы жестко кодировать мой пароль smtp, я пошел с пользовательским секретным вариантом. Однако по какой-то причине каждый раз, когда я пытаюсь восстановить пароль, он возвращается как null. Ошибка:

An unhandled exception occurred while processing the request. ArgumentNullException: Value cannot be null. Parameter name: password MoveNext in MessageServices.cs, line 56

мне было интересно, если кто-то может увидеть, что я пропускаю!

Вот мой MessageService.cs

public class AuthMessageSender : IEmailSender, ISmsSender 
{ 

    public IConfiguration Configuration { get; set; } 

    public AuthMessageSender() 
    { 
     var builder = new ConfigurationBuilder() 
       .SetBasePath(Directory.GetCurrentDirectory()) 
       .AddJsonFile("appsettings.json"); 
     Configuration = builder.Build(); 
    } 
    public async Task SendEmailAsync(string email, string subject, string message, string fullName) 
    { 

     try 
     { 
      var _email = "[email protected]*******.co.uk"; 
      var _epass = Configuration["AdminPassword:Email"]; 
      var _dispName = "Mark ****"; 
      var myMessage = new MimeMessage(); 
      var builder = new BodyBuilder(); 
      myMessage.To.Add(new MailboxAddress(fullName ?? "User", email)); 
      myMessage.From.Add(new MailboxAddress(_dispName, _email)); 
      myMessage.Subject = subject; 
      builder.HtmlBody = message; 
      myMessage.Body = builder.ToMessageBody(); 

      using (SmtpClient smtp = new SmtpClient()) 
      { 
       bool UseSSL = true; 
       string Host = "just22.justhost.com"; 
       int Port = 465; 
       await smtp.ConnectAsync(Host, Port, UseSSL).ConfigureAwait(true); 
       smtp.AuthenticationMechanisms.Remove("XOAUTH2"); 
       smtp.Authenticate(_email, _epass); // Note: only needed if the SMTP server requires authentication 
       await smtp.SendAsync(myMessage).ConfigureAwait(false); 
       await smtp.DisconnectAsync(true).ConfigureAwait(false); 
      } 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 


} 

    public Task SendSmsAsync(string number, string message) 
    { 
     // Plug in your SMS service here to send a text message. 
     return Task.FromResult(0); 
    } 

А вот мой Start.cs

public class Startup 
{ 
    public Startup(IHostingEnvironment env) 
    { 
     var builder = new ConfigurationBuilder() 
      .SetBasePath(env.ContentRootPath) 
      .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 
      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); 

     if (env.IsDevelopment()) 
     { 
      // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 
      builder.AddUserSecrets(); 
     } 

     builder.AddEnvironmentVariables(); 
     Configuration = builder.Build(); 
    } 

    public IConfigurationRoot Configuration { get; } 

    // This method gets called by the runtime. Use this method to add services to the container. 
    public void ConfigureServices(IServiceCollection services) 
    { 
     // Add framework services. 
     services.AddDbContext<ApplicationDbContext>(options => 
      options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); 

     services.AddIdentity<ApplicationUser, IdentityRole>() 
      .AddEntityFrameworkStores<ApplicationDbContext>() 
      .AddDefaultTokenProviders(); 

     services.AddMvc(); 

     // Add application services. 
     services.AddTransient<IEmailSender, AuthMessageSender>(); 
     services.AddTransient<ISmsSender, AuthMessageSender>(); 
     services.AddDistributedMemoryCache(); 
     services.AddSession(); 
    } 

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 
    public async void Configure(IApplicationBuilder app, IHostingEnvironment env, 
     ILoggerFactory loggerFactory, IServiceProvider serviceProvider, ApplicationDbContext context) 
    { 
     loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
     loggerFactory.AddDebug(); 

     if (env.IsDevelopment()) 
     { 
      app.UseDeveloperExceptionPage(); 
      app.UseDatabaseErrorPage(); 
      app.UseBrowserLink(); 
     } 
     else 
     { 
      app.UseExceptionHandler("/Home/Error"); 
     } 

     app.UseStaticFiles(); 
     app.UseSession(); 
     app.UseIdentity(); 

     // Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715 
     app.UseFacebookAuthentication(new FacebookOptions() 
     { 
      AppId = Configuration["Authentication:Facebook:AppId"], 
      AppSecret = Configuration["Authentication:Facebook:AppSecret"] 
     }); 

     app.UseMvc(routes => 
     { 
      routes.MapRoute(
       name: "default", 
       template: "{controller=Home}/{action=Index}/{id?}"); 
     }); 
     await CreateRoles(context, serviceProvider); 
    } 
    private async Task CreateRoles(ApplicationDbContext context, IServiceProvider serviceProvider) 
    { 
     var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>(); 
     var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>(); 
     // Create a list of roles with both name and normalised name attributes 
     List<IdentityRole> roles = new List<IdentityRole>(); 
     roles.Add(new IdentityRole { Name = "Admin", NormalizedName = "ADMIN" }); 
     roles.Add(new IdentityRole { Name = "Member", NormalizedName = "MEMBER" }); 
     roles.Add(new IdentityRole { Name = "Moderator", NormalizedName = "MODERATOR" }); 
     // Check if the role already exists 
     foreach (var role in roles) 
     { 
      var roleExist = await RoleManager.RoleExistsAsync(role.Name); 
      if (!roleExist) 
      { // Add it if it doesn't 
       context.Roles.Add(role); 
       context.SaveChanges(); 
      } 
     } 
     var user = await userManager.FindByEmailAsync("mark****@gmail.com"); 
     if (user != null) 
     { 
      var gotRoles = userManager.GetRolesAsync(user); 
      if (!gotRoles.Equals("Admin")) 
      { 
       await userManager.AddToRoleAsync(user, "Admin"); 
      } 
     } 
    } 
} 

Я проверил, чтобы убедиться, что тайна существует, что она делает, наряду с секретами Facebook аутентификации , которые, похоже, работают очень хорошо.

Если я с жестким кодом пароля, отправляется электронное письмо. Когда я устанавливаю точки останова, я вижу, что пароль действительно нулевый. Я немного в тупике!

Заранее спасибо.

+0

Вы подтвердили, что ваша конфигурация является общедоступной? Я не совсем уверен, как мы можем помочь здесь ... вы могли бы попытаться вытащить секрет пользователя в другом месте, например, где вы используете тот, который находится в вашем файле конфигурации. просто установите точку останова и посмотрите, будет ли он установлен там. В противном случае убедитесь, что вы правильно его написали. Если секрет пользователя действительно существует, не должно быть причин, по которым он будет работать, и не будет. – Kritner

+0

@ Krinter Спасибо за помощь! Когда я попытался получить секрет из StartUp.cs, я обнаружил, что он был доступен, что затем привело меня к рассмотрению кода компоновщика, который я использовал в AuthMessageSender, я скопировал его из Startup.cs точно и добавил назначение переменной в том же блок, который работал с удовольствием. Я добавлю свой ответ сейчас, спасибо еще раз. –

ответ

1

Новый ответ на основе информации, предоставленной @Kritner и по этой ссылке: Access to Configuration object from Startup class

Сначала я создал ПОКО, который имел все мои свойства SMTP, которые должны быть вне поля зрения, например, так:

 public class SmtpConfig 
{ 
    public string EmailDisplayName { get; set; } 
    public string SmtpPassworrd { get; set; } 
    public string SmtpUserEmail { get; set; } 
    public string SmtpHost { get; set; } 
    public int SmtpPort { get; set; } 
} 

Тогда в My Startup.cs Я добавил это ConfigureServices:

  services.Configure<SmtpConfig>(optionsSetup => 
     { 
      //get from appsetings.json file 
      optionsSetup.SmtpPassworrd = Configuration["SMTP:Password"]; 
      optionsSetup.SmtpUserEmail = Configuration["SMTP:Email"]; 
      optionsSetup.SmtpHost = Configuration["SMTP:Host"]; 
      optionsSetup.SmtpPort = Convert.ToInt32(Configuration["SMTP:Port"]); 
     }); 

Наконец я редактировал мои messageServices выглядеть следующим образом:

 public class AuthMessageSender : IEmailSender, ISmsSender 
{ 
    private readonly IOptions<SmtpConfig> _smtpConfig; 
    public IConfiguration Configuration { get; set; } 

    public AuthMessageSender(IOptions<SmtpConfig> smtpConfig) 
    { 
     _smtpConfig = smtpConfig; 
    } 
    public async Task SendEmailAsync(string email, string subject, string message, string fullName) 
    { 

     try 
     { 
      var _email = _smtpConfig.Value.SmtpUserEmail; 
      string _epass = _smtpConfig.Value.SmtpPassworrd; 
      var _dispName = _smtpConfig.Value.EmailDisplayName; 
      var myMessage = new MimeMessage(); 
      var builder = new BodyBuilder(); 
      myMessage.To.Add(new MailboxAddress(fullName ?? "User", email)); 
      myMessage.From.Add(new MailboxAddress(_dispName, _email)); 
      myMessage.Subject = subject; 
      builder.HtmlBody = message; 
      myMessage.Body = builder.ToMessageBody(); 

      using (SmtpClient smtp = new SmtpClient()) 
      { 
       bool UseSSL = true; 
       string Host = _smtpConfig.Value.SmtpHost; 
       int Port = _smtpConfig.Value.SmtpPort; 
       await smtp.ConnectAsync(Host, Port, UseSSL).ConfigureAwait(true); 
       smtp.AuthenticationMechanisms.Remove("XOAUTH2"); 
       smtp.Authenticate(_email, _epass); // Note: only needed if the SMTP server requires authentication 
       await smtp.SendAsync(myMessage).ConfigureAwait(true); 
       await smtp.DisconnectAsync(true).ConfigureAwait(true); 
      } 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 


    } 
+0

, а не перестраивать конфигурацию во всех классах, которые в ней нуждаются, рассмотрите возможность использования предлагаемого здесь решения. Http://stackoverflow.com/a/28953315/2312877 В принципе, вы создадите объект для инъекций, который будет содержать ваши конфигурации, таким образом вы можете вводить настройки в свои классы, а не перестраивать их, что упростит понимание кода, а также будет легче тестировать. – Kritner

+0

Это именно то, что мне нужно, спасибо! Мне просто нужно было снова получить доступ к информации в настройках моего приложения, так что это поможет в производительности и отладке! Теперь я фактически переместил все мои настройки smtp в мои пользовательские секреты (электронная почта пользователя, хост и т. Д.), И мой код выглядит намного чище без информации! –

Смежные вопросы