I am using VS2013 with Entity Framework 6.1 against SQL 2012.
When I use Code First to create my classes and tables in Dev it works fine.
When I go to publish via Web Deploy to my third party host everything deploys but none of the tables are created in the DB. The connection string/s contain the appropriate username and password for a user that has table create access to the DB. (Tested because I use the same login/password via SSMS
to create tables on the hosted SQL server successfully)
The Database publish connection string is being made correctly and has the correct values.
When I deploy the ASP.Net MVC app with the Execute Code First Migrations checkbox marked the app throws a 500 error on the hosted server.
Any thoughts on what might be wrong?
It sounds like this is a misunderstanding of how the VS Web Deployment feature handles EFCF Migrations.
Normally (non-EFCF), VS publishes your files to the remote server and updates your database schema. By the time the deployment is complete, all changes have been applied.
With EFCF migrations, this is not the case. VS's deployment will modify your web.config to set up the connection strings needed for the database. This is reflected in the published files, but the DB has not been touched at all yet. The changes to the DB don't take place until the migrations code runs. This happens by default the first time your code initializes your DbContext; the DbInitializer will execute any migrations that have not been applied. Generally, this means you have to request a page from your site to trigger this process.
To expound a little bit on my comment:
Manually changing the schema is not a good fix for this, as it will then block the migration from being able to run later ("table Foo already exists" type errors).
If you've made changes to the DB that are incompatible with the Migrations code, you'll get an exception from EF. For example, you might have this migration:
public override void Up()
{
CreateTable(
"dbo.Foo",
c => new
{
Id = c.Int(nullable: false, identity: true),
Value = c.String(nullable: false, maxLength: 200),
})
.PrimaryKey(t => t.Id);
}
If you've manually created table Foo (e.g. because you didn't see it after deployment), EF can no longer apply this migration, and throws an exception. This can be the cause of the HTTP 500 errors you were seeing.
For some reason I have to determine there was an EntityFramework section added to the deployed Web.config that was not located in my local version of Web.config. The error was being caused by there being a EntityFramework section but there was no section descriptor specifying that there was an EntityFramework section.
I added the section descriptor and everything works correctly.
I'm not sure why the transform was happening when things were being deployed but the transform was incomplete.
I would set up error pages in your application.
In your Web.config
under <system.web>
you would have
<customErrors mode="On" defaultRedirect="~/Error/Index">
<error statusCode="400" redirect="~/Error/Error400" />
<error statusCode="403" redirect="~/Error/Error403" />
<error statusCode="404" redirect="~/Error/Error404" />
</customErrors>
So, the defaultRedirect
would catch the 500 error.
Your Error
controller could look as follows.
public class ErrorController : Controller
{
public ActionResult Index()
{
return View("Error");
}
public ActionResult Error400()
{
return View("Error400");
}
public ActionResult Error403()
{
return View("Error403");
}
public ActionResult Error404()
{
return View("Error404");
}
}
And your Error
view (I have it in Views\Shared
directory) woul look as follows.
@{
Layout = "~/Views/Shared/_Layout_Blank.cshtml";
ViewBag.Title = "Application Error";
}
@model System.Web.Mvc.HandleErrorInfo
<h1>Application Error</h1>
@if (Model != null)
{
<div>
Location: @Model.ControllerName/@Model.ActionName
<br />
Message: @Model.Exception.Message
</div>
}
else
{
<div>
You've reached this page in error.
</div>
}