问题描述
尝试将我的MVC应用程序发布到生产环境时,从localdb切换到sql生产数据库时遇到问题。
即使我更改了发行版web.config中的defaultconnection连接字符串,它似乎仍想访问localDB。每当我尝试在已发布的程序包上登录/注册用户时,它都会尝试访问localDB(应注意,它在调试时工作得很好)
请参见下面的代码段
Web.config
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application,please visit
https://go.microsoft.com/fwlink/?LinkId=301880
-->
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration,visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection,EntityFramework,Version=6.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSsqlLocalDB;AttachDbFilename=|DataDirectory|\aspnet-Questionnaire-20200826090735.mdf;Initial Catalog=aspnet-Questionnaire-20200826090735;Integrated Security=true" providerName="System.Data.sqlClient" />
<add name="Questionnaire_managementEntities" connectionString="......" providerName="System.Data.EntityClient" />
<add name="CWDataSetsEntities" connectionString="........" providerName="System.Data.EntityClient" />
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
<system.web>
<authentication mode="None" />
<roleManager enabled="true" />
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2" />
</system.web>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" />
<bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.9.0" newVersion="3.1.9.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory,EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.sqlClient" type="System.Data.Entity.sqlServer.sqlProviderServices,EntityFramework.sqlServer" />
</providers>
</entityFramework>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider,Microsoft.CodeDom.Providers.DotNetCompilerPlatform,Version=2.0.1.0,PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /Nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider,PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /Nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+" />
</compilers>
</system.codedom>
</configuration>
web.release.config
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
In the example below,the "SetAttributes" transform will change the value of
"connectionString" to use "ReleasesqlServer" only when the "Match" locator
finds an attribute "name" that has a value of "MyDB".
<connectionStrings>
<add name="MyDB"
connectionString="Data Source=ReleasesqlServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
-->
<connectionStrings>
<add name="DefaultConnection"
connectionString="data source=lonvmdp02;initial catalog=Questionnaire_login;user id=cwdataagent;password=Pa$$w0rd;MultipleActiveResultSets=True;"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<!--
In the example below,the "Replace" transform will replace the entire
<customErrors> section of your Web.config file.
Note that because there is only one customErrors section under the
<system.web> node,there is no need to use the "xdt:Locator" attribute.
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
</configuration>
管理控制器
[Authorize]
public class ManageController : Controller
{
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
public ManageController()
{
}
public ManageController(ApplicationUserManager userManager,ApplicationSignInManager signInManager)
{
UserManager = userManager;
SignInManager = signInManager;
}
public ApplicationSignInManager SignInManager
{
get
{
return _signInManager ?? HttpContext.GetowinContext().Get<ApplicationSignInManager>();
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetowinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
}
IdentityConfig
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Questionnaire.Models;
namespace Questionnaire
{
public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
// Plug in your email service here to send an email.
return Task.Fromresult(0);
}
}
public class SmsService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
// Plug in your SMS service here to send a text message.
return Task.Fromresult(0);
}
}
// Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application.
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options,IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
requiredLength = 6,RequireNonLetterOrDigit = true,requiredigit = true,RequireLowercase = true,RequireUppercase = true,};
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug it in here.
manager.RegisterTwoFactorProvider("Phone Code",new PhoneNumberTokenProvider<ApplicationUser>
{
messageformat = "Your security code is {0}"
});
manager.RegisterTwoFactorProvider("Email Code",new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",BodyFormat = "Your security code is {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
// Configure the application sign-in manager which is used in this application.
public class ApplicationSignInManager : SignInManager<ApplicationUser,string>
{
public ApplicationSignInManager(ApplicationUserManager userManager,IAuthenticationManager authenticationManager)
: base(userManager,authenticationManager)
{
}
public override Task<ClaimsIdentity> createuserIdentityAsync(ApplicationUser user)
{
return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options,IOwinContext context)
{
return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(),context.Authentication);
}
}
}
IdentityModel
using System.Data.Entity;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
namespace Questionnaire.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class,please visit https://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
public string Country { get; set; }
public bool is_verified { get; set; }
public string Verified_at { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationoptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this,DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim("Country",this.Country.ToString()));
userIdentity.AddClaim(new Claim("is_verified",this.is_verified.ToString()));
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection",throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
}
IdentityExtension(用于启用更多身份功能的扩展名)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Web;
namespace Questionnaire.Models.Extensions
{
public static class IdentityExtensions
{
public static string GetCountry(this IIdentity identity)
{
var claim = ((ClaimsIdentity)identity).FindFirst("Country");
// Test for null to avoid issues during local testing
return (claim != null) ? claim.Value : string.Empty;
}
public static string Is_Verified(this IIdentity identity)
{
var claim = ((ClaimsIdentity)identity).FindFirst("is_verified");
if(claim==null)
{
return "NULL";
}
return (claim.Value) ;
}
}
}
迁移配置(这样做是为了将applicationdbconcext与localdb同步以修复错误)
namespace Questionnaire.Migrations
{
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
internal sealed class Configuration : DbMigrationsConfiguration<Questionnaire.Models.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "Questionnaire.Models.ApplicationDbContext";
}
protected override void Seed(Questionnaire.Models.ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
}
}
}
迁移记录-TestMigration
namespace Questionnaire.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class testmigration : DbMigration
{
public override void Up()
{
AddColumn("dbo.AspNetUsers","Country",c => c.String());
AddColumn("dbo.AspNetUsers","is_verified",c => c.Boolean(nullable: false));
AddColumn("dbo.AspNetUsers","Verified_at",c => c.String());
}
public override void Down()
{
DropColumn("dbo.AspNetUsers","Verified_at");
DropColumn("dbo.AspNetUsers","is_verified");
DropColumn("dbo.AspNetUsers","Country");
}
}
}
迁移记录-initialcreate
namespace Questionnaire.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class InitialCreate : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.AspNetRoles",c => new
{
Id = c.String(nullable: false,maxLength: 128),Name = c.String(nullable: false,maxLength: 256),})
.PrimaryKey(t => t.Id)
.Index(t => t.Name,unique: true,name: "RoleNameIndex");
CreateTable(
"dbo.AspNetUserRoles",c => new
{
UserId = c.String(nullable: false,RoleId = c.String(nullable: false,})
.PrimaryKey(t => new { t.UserId,t.RoleId })
.ForeignKey("dbo.AspNetRoles",t => t.RoleId,cascadeDelete: true)
.ForeignKey("dbo.AspNetUsers",t => t.UserId,cascadeDelete: true)
.Index(t => t.UserId)
.Index(t => t.RoleId);
CreateTable(
"dbo.AspNetUsers",Email = c.String(maxLength: 256),EmailConfirmed = c.Boolean(nullable: false),PasswordHash = c.String(),SecurityStamp = c.String(),PhoneNumber = c.String(),PhoneNumberConfirmed = c.Boolean(nullable: false),TwoFactorEnabled = c.Boolean(nullable: false),LockoutEndDateUtc = c.DateTime(),LockoutEnabled = c.Boolean(nullable: false),AccessFailedCount = c.Int(nullable: false),UserName = c.String(nullable: false,})
.PrimaryKey(t => t.Id)
.Index(t => t.UserName,name: "UserNameIndex");
CreateTable(
"dbo.AspNetUserClaims",c => new
{
Id = c.Int(nullable: false,identity: true),UserId = c.String(nullable: false,ClaimType = c.String(),ClaimValue = c.String(),})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.AspNetUsers",cascadeDelete: true)
.Index(t => t.UserId);
CreateTable(
"dbo.AspNetUserLogins",c => new
{
LoginProvider = c.String(nullable: false,ProviderKey = c.String(nullable: false,})
.PrimaryKey(t => new { t.LoginProvider,t.ProviderKey,t.UserId })
.ForeignKey("dbo.AspNetUsers",cascadeDelete: true)
.Index(t => t.UserId);
}
public override void Down()
{
DropForeignKey("dbo.AspNetUserRoles","UserId","dbo.AspNetUsers");
DropForeignKey("dbo.AspNetUserLogins","dbo.AspNetUsers");
DropForeignKey("dbo.AspNetUserClaims","dbo.AspNetUsers");
DropForeignKey("dbo.AspNetUserRoles","RoleId","dbo.AspNetRoles");
DropIndex("dbo.AspNetUserLogins",new[] { "UserId" });
DropIndex("dbo.AspNetUserClaims",new[] { "UserId" });
DropIndex("dbo.AspNetUsers","UserNameIndex");
DropIndex("dbo.AspNetUserRoles",new[] { "RoleId" });
DropIndex("dbo.AspNetUserRoles",new[] { "UserId" });
DropIndex("dbo.AspNetRoles","RoleNameIndex");
DropTable("dbo.AspNetUserLogins");
DropTable("dbo.AspNetUserClaims");
DropTable("dbo.AspNetUsers");
DropTable("dbo.AspNetUserRoles");
DropTable("dbo.AspNetRoles");
}
}
}
如果您需要查看代码的任何其他部分,请告诉我。 就像我说的。它可以使用调试完美地运行,但是当我尝试通过IIS发行并运行时,它仍然尝试访问本地数据库
https://www.youtube.com/watch?v=fis26HvvDII&t=35923s
解决方法
帐户控制器(我使用register2函数进行注册)
[Authorize]
public class AccountController : Controller
{
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager,ApplicationSignInManager signInManager )
{
UserManager = userManager;
SignInManager = signInManager;
}
public ApplicationSignInManager SignInManager
{
get
{
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register2(RegisterViewModel model)
{
if (ModelState.IsValid)
{
Questionnaire_managementEntities db = new Questionnaire_managementEntities();
var userexist = db.Users.Where(x => x.Email == model.Email).Select(x => x);
//if(userexist.Count()==0)
//{
// Questionnaire.User Newuser = new User();
// Newuser.Country = model.Country;
// Newuser.Email = model.Email;
// Newuser.Is_verified = false;
// var md5 = new MD5CryptoServiceProvider();
// var password = Encoding.ASCII.GetBytes(model.Password);
// var hash = md5.ComputeHash(password);
// Newuser.Password = hash.ToString() ;
// return RedirectToAction("Index","Home");
//}
//else
//{
// ModelState.AddModelError("","User Account Already Exist");
//}
var user = new ApplicationUser { UserName = model.Email,Email = model.Email,Country = model.Country };
var result = await UserManager.CreateAsync(user,model.Password);
string[] users = {user.UserName};
IdentityUserRole roles = new IdentityUserRole();
roles.RoleId = "2";
roles.UserId = user.Id;
user.Roles.Add(roles);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user,isPersistent: false,rememberBrowser: false);
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail","Account",new { userId = user.Id,code = code },protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id,"Confirm your account","Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");
return RedirectToAction("Index","Home");
}
AddErrors(result);
}
// If we got this far,something failed,redisplay form
return View(model);
}
}
,
将此添加到我的web.config,
<roleManager enabled="true" defaultProvider="CustomizedRoleProvider">
<providers>
<add name="CustomizedRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="DefaultConnection" />
</providers>
</roleManager>
在我的Visual Studio命令行中运行aspnet_regsql命令并完成设置后,解决了我的问题。
regsql命令添加了一堆我没有使用的表,但是它还添加了一些我的登录数据库所需的存储过程。