最近碰到一个奇怪的问题,发生在一个典型的Microsoft Azure云应用开发场景:利用Azure WebSites快速开发云Web应用,同时利用SQL Database来存储数据并提供数据服务;使用Entity Framework,可以快捷、高效地在客户端建立数据模型,便于访问SQL Database中的数据并进行交互。
问题是:为了开发方便,在本地Visual Studio开发环境中开发WebSites应用,连接到Azure上的SQL Database的时候,一切正常;但将本地代码部署到Azure上的WebSites的时候,发现SQL Database数据连接出错。
典型的错误提示信息如下:
Server Error in '/' Application.
The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentException: The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.
问题出在哪里呢?让我们从本地和Azure WebSites两个环境的对比开始分析。
在本地环境中,我们可以在Visual Studio中连接到一个已经建好的SQL Database数据库。在一个解决方案中,添加一个“ADO.NET Entity Data Model”,如下所示:
选择EF Designer from database:
在这里,会看到生成的连接串(Connection String)如下:
然后,即可以选择SQL Database中选中的表进行相关的数据操作。如下:
OK,测试结果正常。
查看项目文件,在app.config文件中,可以看来连接串,例如:
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=tcp:[SERVERNAME].database.chinacloudapi.cn,1433;initial catalog=[CATNAME]; persist security info=True; user id=[USERID];password=[PASSWORD];" providerName="System.Data.SqlClient" />
<add name="[ENTITYNAME]" connectionString="metadata=res://*/ [MODEL].csdl|res://*/ [MODEL].ssdl|res://*/ [MODEL].msl; provider=System.Data.SqlClient;provider connection string="data source=tcp:[SERVERNAME].database.chinacloudapi.cn,1433;initial catalog=[CATNAME]; persist security info=True; user id=[USERID];password=[PASSWORD];multipleactiveresultsets=True;App=EntityFramework""
providerName="System.Data.EntityClient"/>
</connectionStrings>
请注意红色字体部分,具体原因稍后在解释。
下面再看一下Azure Websites端。一般说来,会将Web Site和已有的SQL Database结合,如下:
请注意,在这里我们经常会选择“DefaultConnection”作为数据库连接串的名称。
而在管理门户(Management Portal)上查看连接串,如下图:
可以看到Web Site的连接串,如下,请注意,这里就是“DefaultConnection”的连接串。
经过调试发现,当WebSites中使用的连接串名称(例如“DefaultConnection”),如果和Visual Studio中解决方案的配置文件中设定的连接串名称冲突的话,将有可能出现文章开头出现的问题。
当应用部署到Azure WebSites之后,Entity Framework在调用连接串的时候,会把WebSites中的连接串首先使用,从而使EntityFramework无法调用自己的模型。
而发生这个问题的关键应该是Entity Framework的工作机理,特别是对连接串的选择上。
对于Entity Framework,可以在GitHub上得到相关的技术资源、源代码等:
Scott Gu的博客对于EntityFramework的三个开发模式:database first,model first和code first做了精彩剖析。
详见: http://weblogs.asp.net/scottgu/code-first-development-with-entity-framework-4
当创立WebSites时Azure所提供的连接串,与使用Visual Studio创建解决方案是定义的连接串在名称上冲突的时候,一个可以考虑的解决方法就是定义不同的名称,然后重新部署和调试。