ASP.NET Core開發常見問題


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

MIME 參考手冊

文件下載

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 下載文件,這是此類文件保存到“下載”文件夾的原因。

msSaveBlob:只提供一個保存按鈕
msSaveOrOpenBlob:提供保存和打開按鈕
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);
    }
}
View Code

后端:

 [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; //沒什么用處
            }
        }
View Code

參考:

jQuery 利用其 AJAX 下載后端返回的 application/octet-stream 二進制數據

Vue responseType中blob和arrayBuffer下載文件以及JSON處理

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM