已部署Azure Function缺失Entity Framework .edmx文件报FileNotFoundException错误
你遇到的故障与Blob存储权限无关,是Entity Framework 6的模型缓存机制与Azure Function运行环境的文件权限限制共同导致的。
根因说明
EF6默认的DefaultDbModelStore组件会在应用启动后首次访问数据库时,将编译好的实体模型以.edmx格式写入程序所在的bin目录做缓存,避免每次启动重复编译模型损耗性能:
- 本地运行
func start时,本地项目的bin目录为可写权限,运行时可以正常生成缓存文件,因此不会报错 - 部署到Azure Function App后,
D:\home\site\wwwroot\bin目录默认为只读状态,EF尝试写入.edmx缓存文件失败,读取时就会抛出你收到的FileNotFoundException异常
你收到的完整错误如下:
2021-10-18T23:37:07.588 [Error] Executed 'MyFunction' (Failed, Duration=1807ms)
Autofac.Core.DependencyResolutionException : An exception was thrown while activating
Autofac.Core.DependencyResolutionException : An exception was thrown while invoking the constructor 'Void .ctor()' on type 'Repository'.
System.IO.FileNotFoundException : Could not find file 'D:\home\site\wwwroot\bin\DAOEntities.edmx'.
(后续堆栈省略)
可落地的解决方案
你可以任选以下任意一种方案解决该问题:
方案1:直接禁用EF模型缓存(适合开发测试环境,修改成本最低)
在你的DbContext静态构造函数中添加代码关闭模型存储即可,缺点是每次冷启动都要重新编译模型,会增加首次访问数据库的耗时:static DAOEntities() { DbConfiguration.Loaded += (_, args) => { args.ReplaceService<DbModelStore>((_, __) => null); }; }方案2:自定义模型缓存路径(适合生产环境,性能无损耗)
Azure Function运行时提供了可写的临时目录(对应环境变量TEMP),你可以自定义模型存储类将缓存写入该目录:public class TempDirModelStore : DefaultDbModelStore { public TempDirModelStore() : base(Path.GetTempPath()) { } } // 在DbContext静态构造函数中注册 static DAOEntities() { DbConfiguration.Loaded += (_, args) => { args.ReplaceService<DbModelStore>((_, __) => new TempDirModelStore()); }; }方案3:预生成模型视图(性能最优,适合对冷启动速度要求高的生产场景)
使用EF官方的预生成视图工具,在项目构建阶段就将模型编译为嵌入资源打包到程序集,运行时完全不需要生成缓存文件,也不会额外增加冷启动耗时。
内容的提问来源于stack exchange,提问作者xchg ax ax

