如何在Asp.Net Core 2.0 WebApi中写入wwwroot文件(无需改服务器权限)
解决ASP.NET中POST请求写入文件权限被拒的问题(无需修改服务器权限)
嘿,这个权限坑我之前踩过!不用改服务器权限的话,有几个实用的方案可以解决:
1. 切换到应用专属的私有存储路径
wwwroot是静态文件目录,默认权限配置通常更偏向只读,尤其是生产环境。你可以改用应用根目录下的专用文件夹来存需要写入的文件,比如新建一个Data文件夹——应用进程对自己的目录肯定有读写权限。
代码示例:
首先在控制器里注入IWebHostEnvironment(ASP.NET Core的标配服务):
private readonly IWebHostEnvironment _webHostEnv; public YourApiController(IWebHostEnvironment webHostEnv) { _webHostEnv = webHostEnv; }
然后在POST方法里构建安全的文件路径:
// 构建应用根目录下Data文件夹的绝对路径 var storagePath = Path.Combine(_webHostEnv.ContentRootPath, "Data"); // 确保文件夹存在,避免写入时报错 Directory.CreateDirectory(storagePath); var filePath = Path.Combine(storagePath, "Keys.json"); // 剩下的读写逻辑和你原来的一致 var result = new List<FireBaseKeysModel>(); if (File.Exists(filePath)) { var initialJson = File.ReadAllText(filePath); var convertedJson = JsonConvert.DeserializeObject<List<FireBaseKeysModel>>(initialJson); if (convertedJson != null) { result.AddRange(convertedJson); } } result.Add(new FireBaseKeysModel { AccountId = accountId, AditionalInfo = addicionalInfo, DeviceInfo = deviceInfo, RegistrationKey = registrationKey, ClientId = clientId }); var json = JsonConvert.SerializeObject(result.ToArray()); File.WriteAllText(filePath, json);
2. 明确指定wwwroot的绝对路径(如果非要用wwwroot)
如果你坚持要存在wwwroot里,别用相对路径——POST请求的当前工作目录可能和GET不一样,导致权限上下文出错。用IWebHostEnvironment.WebRootPath获取wwwroot的绝对路径:
var wwwrootPath = _webHostEnv.WebRootPath; var keysFolderPath = Path.Combine(wwwrootPath, "Keys"); Directory.CreateDirectory(keysFolderPath); // 确保文件夹存在 var filePath = Path.Combine(keysFolderPath, "Keys.json");
这个方法不一定100%生效,但比相对路径靠谱很多,因为它明确指向了正确的目录。
3. 内存缓存+定时持久化(适合写入不频繁的场景)
如果你的密钥写入操作不是特别频繁,可以先把数据存在内存缓存里,再用后台任务定期写入文件。这样既避免了实时写入的权限冲突,还能提升接口响应速度。
代码示例:
先注入IMemoryCache:
private readonly IMemoryCache _memoryCache; private readonly IWebHostEnvironment _webHostEnv; private const string KeysCacheKey = "FirebaseKeysCache"; public YourApiController(IMemoryCache memoryCache, IWebHostEnvironment webHostEnv) { _memoryCache = memoryCache; _webHostEnv = webHostEnv; }
然后在POST方法里操作缓存:
// 先从缓存读取数据,没有的话从文件加载 if (!_memoryCache.TryGetValue(KeysCacheKey, out List<FireBaseKeysModel> keysList)) { var filePath = Path.Combine(_webHostEnv.ContentRootPath, "Data", "Keys.json"); keysList = new List<FireBaseKeysModel>(); if (File.Exists(filePath)) { var initialJson = File.ReadAllText(filePath); keysList = JsonConvert.DeserializeObject<List<FireBaseKeysModel>>(initialJson) ?? new List<FireBaseKeysModel>(); } // 缓存1小时,滑动过期 _memoryCache.Set(KeysCacheKey, keysList, new MemoryCacheEntryOptions { SlidingExpiration = TimeSpan.FromHours(1) }); } // 添加新密钥到缓存 keysList.Add(new FireBaseKeysModel { AccountId = accountId, AditionalInfo = addicionalInfo, DeviceInfo = deviceInfo, RegistrationKey = registrationKey, ClientId = clientId }); _memoryCache.Set(KeysCacheKey, keysList); // 启动后台任务写入文件(生产环境建议用IHostedService或Hangfire替代Task.Run) Task.Run(() => { var filePath = Path.Combine(_webHostEnv.ContentRootPath, "Data", "Keys.json"); var json = JsonConvert.SerializeObject(keysList.ToArray()); File.WriteAllText(filePath, json); });
额外注意点:
不管用哪个方案,都要先检查并创建目标文件夹,不然File.WriteAllText会因为文件夹不存在报错,记得加Directory.CreateDirectory(Path.GetDirectoryName(filePath));。
内容的提问来源于stack exchange,提问作者THingamagick




