ASP.NET Core中返回 json 數據首字母大小寫問題
在asp.net core中使用ajax請求動態綁定數據時遇到問題:
后台返回數據字段首字母為定義的大寫,返回的數據沒有問題;但是在前台得到的數據,字段首字母卻變成了小寫
此時用定義的首字母大寫字段去接收數據會顯示undefined,這是因為在asp.net core中json序列化默認使用駝峰格式處理字段,首字母變成小寫,所以獲取不到數據。
解決方法:在Startup類的ConfigureServices()方法中進行配置,DefaultContractResolver() 原樣輸出,返回的 json 與后台定義一致
public void ConfigureServices(IServiceCollection services) { ... services.AddMvc().AddJsonOptions(opt => { opt.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();//json字符串大小寫原樣輸出 }); }
此時json字符串字段首字母大小與后台定義一致
參考:ASP.NET Core中返回 json 數據首字母大小寫問題
WebAPI——修改默認監聽端口
添加host.json文件
{ "urls": "https://localhost:44389;http://localhost:44380" }
在Program.cs中修改CreateWebHostBuilder方法
public static IWebHostBuilder CreateWebHostBuilder(string[] args) { var configuration = new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory) .AddJsonFile("host.json") .Build(); var url = configuration["urls"]; return WebHost.CreateDefaultBuilder(args) .UseUrls(url) .UseStartup<Startup>(); }
參考官網:ASP.NET Core Web 主機
HttpClient Post json參數請求
被請求的接口代碼如下:
//被請求接口 // POST api/values [HttpPost] public MyProperty Post([FromBody] MyProperty value) { return value; } //參數 public class MyProperty { public int ID { get; set; } public string Name { get; set; } }
注:若提交報錯:通過post提交Json數據時,接口返回,"{\"\":[\"Unexpected character encountered while parsing value: {. Path '', line 1, position 1.\"]}"
則可能是因為參數 寫成了string類型([FromBody] string value)
使用HttpClient的PostAsync方法發送Json數據請求
public class JsonContent : StringContent { public JsonContent(object obj) : base(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json") { } } public static string HttpClientPost(string url, object datajson) { HttpClient httpClient = new HttpClient();//http對象 //表頭參數 httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); //轉為鏈接需要的格式 HttpContent httpContent = new JsonContent(datajson); //請求 HttpResponseMessage response = httpClient.PostAsync(url, httpContent).Result; if (response.IsSuccessStatusCode) { Task<string> t = response.Content.ReadAsStringAsync(); if (t != null) { return t.Result; } } return ""; }
調用
//調用 MyProperty myProperty = new MyProperty(); myProperty.ID = 666; myProperty.Name = "Tom貓"; var result = HttpClientPost("http://localhost:59958/api/values", myProperty); Console.WriteLine(result);
wwwroot目錄下文件訪問不了
private IHostingEnvironment _host; public NewsController(IHostingEnvironment host) { this._host = host; } string webRootPath = _host.WebRootPath; //獲取的即是wwwroot
net core 3.1中 推薦用IHostEnvironment,路徑獲取用:Path.Combine(_host.ContentRootPath, "wwwroot")
方案:允許站點不識別content-type下載文件(即:不受mime類型限制下載)
對於netcore的web項目而言,內置了一些content-type允許下載的文件類型,eg,常見的image、pdf、zip等,有些卻未運行,eg:nupkg、apk,
要想.apk,.nupkg.cs等后綴的文件不被限制,我們可以:
app.UseStaticFiles(new StaticFileOptions { //設置不限制content-type ServeUnknownFileTypes = true });
上面例子我們能夠使用 ServeUnknownFileTypes = true; 直接設置無限制下載文件類型,這種通常不是太好或者說不允許,亦或者不常說的不安全吧;如果我們只需要增加.nupkg和.apk后綴的文件的下載,那么可以通過如下代碼來添加mime類型,如:
app.UseStaticFiles(new StaticFileOptions { //ServeUnknownFileTypes = true ContentTypeProvider = new FileExtensionContentTypeProvider(new Dictionary<string, string> { { ".apk","application/vnd.android.package-archive"}, { ".nupkg","application/zip"} }) });
再比如要下載一個byte[]寫入的 xx.tsa二進制文件,可以加一個:{ ".tsa", "application/octet-stream" }
參考:
StaticFiles 之 FileExtensionContentTypeProvider
文件下載
1、后端直接返回 文件的地址,前端定位,直接下載
后端:
ViewBag.zipFile = zipFile ; // zipFile文件在服務器上的絕對路徑
html:
<el-button type="primary" @@click="onDownTSA('@ViewBag.zipFile')">下載文件(.zip)</el-button>
onDownTSA(zipFile) {
window.open(zipFile, "_blank") }
2、后端返回文件對象,前端請求下載
- 下載完不需要返回值
onDownTSA(zipName) { downloadFiles("/ApplyTimeStamp/DownTsaFile", { zipName: zipName }); } //無返回值 function downloadFiles(url, params) { try { var form = document.createElement("form"); form.id = "downloadForm"; form.style.display = "none"; form.target = ""; form.method = "post"; form.action = url; for (var key in params) { var input = document.createElement("input"); input.type = "hidden"; input.name = key; input.value = params[key]; form.appendChild(input); } document.body.appendChild(form); form.submit(); document.body.removeChild(form); } catch (ex) { Vue.prototype.$message.error(ex); } }
后端:
[Description("下載證明文件")] public async Task<IActionResult> DownTsaFile(string zipName) { try { byte[] bytes = null; zipName = zipName.Trim(); string path = Path.Combine("wwwroot", WebConstant.TsaFileDirName, zipName); if (System.IO.File.Exists(path)) { bytes = await System.IO.File.ReadAllBytesAsync(path); } return File(bytes, "application/octet-stream", zipName); } catch (Exception ex) { LogHelper.Error(ex.Message, ex); ObjectResult objectResult = new ObjectResult(new ResultDTO()); return objectResult; //沒什么用處 } }
- 下載完后需要返回值
使用 Blob 構造函數可以直接在客戶端上創建和操作 Blob(通常等效於一個文件)。
Internet Explorer 10 的 msSaveBlob 和 msSaveOrOpenBlob 方法允許用戶在客戶端上保存文件,方法如同從 Internet 下載文件,這是此類文件保存到“下載”文件夾的原因。

onDownTSA(zipName) { downloadFiles("/ApplyTimeStamp/DownTsaFile", { zipName: zipName }); } //有返回值 function downloadFiles(url, params) { try { var form = document.createElement("form"); form.id = "downloadForm"; form.style.display = "none"; form.target = ""; form.method = "post"; let filename = ""; for (var key in params) { var input = document.createElement("input"); input.type = "hidden"; input.name = key; input.value = params[key]; filename = input.value; form.appendChild(input); } document.body.appendChild(form); let dataN = new FormData(form); axios.post(url, dataN, { responseType: 'blob' }).then(response => { var data = response.data; if (response.status == 200) { //請求成功 if (window.navigator.msSaveOrOpenBlob) { let blob = new Blob([data]) navigator.msSaveBlob(blob, filename); } else { let blob = new Blob([data]) var link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = filename; link.click(); window.URL.revokeObjectURL(link.href); } Vue.prototype.$message({ message: '下載成功', type: 'success' }); document.body.removeChild(form); url = "/ApplyTimeStamp/Index"; location.href = url; } }).catch((ex) => { //請求失敗 if (ex.response.status == 404) { Vue.prototype.$message.error('文件不存在或者已被下載!'); } else if (ex.response.status == 400) { Vue.prototype.$message.error('參數異常:文件名為空異常!'); } }); } catch (ex) { Vue.prototype.$message.error(ex); } }
后端:

[Description("下載證明文件")] public async Task<IActionResult> DownTsaFile(string zipName) { var error = new ResultDTO(0, ""); try { if (!string.IsNullOrEmpty(zipName)) { byte[] bytes = null; zipName = zipName.Trim(); string path = Path.Combine("wwwroot", WebConstant.TsaFileDirName, zipName); if (System.IO.File.Exists(path)) { bytes = await System.IO.File.ReadAllBytesAsync(path); } else { throw new Exception($"文件不存在或者已被下載"); } if (System.IO.File.Exists(path)) { System.IO.File.Delete(path); } Response.StatusCode = (int)HttpStatusCode.OK; //HttpUtility.UrlEncode(zipName,Encoding.UTF8) return File(bytes, "application/octet-stream", zipName); } else { error.Code = -1; error.Msg = $"參數異常:文件名為空異常"; ObjectResult objectResult = new ObjectResult(error); Response.StatusCode = (int)HttpStatusCode.BadRequest; return objectResult; } } catch (Exception ex) { LogHelper.Error(ex.Message, ex); error.Code = -1; error.Msg = $"下載文件異常:{ex.Message}"; ObjectResult objectResult = new ObjectResult(error); Response.StatusCode = (int)HttpStatusCode.NotFound; return objectResult; //沒什么用處 } }
參考:
jQuery 利用其 AJAX 下載后端返回的 application/octet-stream 二進制數據
Vue responseType中blob和arrayBuffer下載文件以及JSON處理