iT邦幫忙

0

c# asp.mvc webapi 如何post資料後將Jobeject轉成dto透過savechange存到資料庫裡

目前想要將我前端的下拉選單的id跟值POST到C#的WEB API存到DB裡,之前因為JSON資料型態不是物件包array的形式我可以直接參數使用[FromBody]List model的方式讓我的資料對映到我的類別裡用foreach的方式給值用savechange更新DB但現在繼續用上面的方式CONsole.log會顯示為0可能因為型態是array。所以我改用[FromBody]Jobject model的方式去接可以顯示值但就不知道怎麼讓它去轉換成dto讓我去更新db。資料的json如下
{score: "[{"selectedEmpValue":"0426052","scoreId":"34","sco…pValue":"0426052","scoreId":"35","scoreVal":"2"}]"}

 function SaveScore() {
            var objlist = [];
            var selectedEmpValue = $('#Emps option:selected').val();
            var obj;
            $('.table select').each(function () {
                var scoreVal = $(this).val();
                var scoreId = $(this).attr("id");
                if ($.trim(scoreVal) > 0) {
                    objlist.push({ selectedEmpValue, scoreId, scoreVal } );
                    //obj = JSON.stringify(objlist);


                } else {
                    //console.log($(this).attr("id") + ":" + scoreVal+"not");
                }

            })
            console.log(objlist);
            UpdateScore(objlist);
        }
 //呼叫UpdateScore()用ajax post到後端
 function UpdateScore(objlist) {
            $.ajax({
                url: 'http://HaoweiLu.com/DnaAPI/api/Values/',
                type: 'POST',
                crossDomain: true,
                cache: false,
                async: false,
                dataType: 'json',
                data: { score: JSON.stringify(objlist) },
            success: function (data) {
                alert('接收成功');
                console.log(data);
            }
        });
    }

後端webapi如下還有dto的類別

 public class RootDTO
    {
        public List<Obj> ob { get; set; }
    }
    public class Obj
    {
        public string selectedEmpValue { get; set; }
        public string scoreId { get; set; }
        public string scoreVal { get; set; }

    }
 //目前接資料的方式但不知道如何對映到我的dto因為變了2層且就算硬轉換顯示也為0
    [HttpPost]
        public IHttpActionResult Post([FromBody]JObject model)
        {
            //JToken jToken = model["score"];
            //var a = model.ToString();
            //JObject jObject = JObject.Parse(a);
            //var tes = JsonConvert.DeserializeObject<RootDTO>(a);
            return Ok(model);
        }
 //以前的方式,希望可以透過這種方式來對映但用這個的話我就接不到值會是0但以前的dto只有一層因為我在前端的ajax中的data少了{score:}直接放data:JSON.stringify(objlist),
 [HttpPost]
        public ActionResult Update(List<Obj> model)
        {
            try
            {
                EmpContext db = new EmpContext();
                hao_message test = new hao_message();

                foreach (var item in model)
                {
                    test.emp = item.selectedEmpValue;
                    test.dep = item.scoreId;
                    test.score = int.Parse(item.scoreVal);
                    test.header = "測試3";

                    db.hao_message.Add(test);
                    db.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return RedirectToAction("Index");
          
        }
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

1
Homura
iT邦高手 1 級 ‧ 2021-12-10 10:48:45
最佳解答

web api有model binding的功能
請直接用定義好的model放在controller參數上面會幫你轉換好..
就像你原本的寫法

以前的方式,希望可以透過這種方式來對映但用這個的話我就接不到值會是0但以前的dto只有一層因為我在前端的ajax中的data少了{score:}直接放data:JSON.stringify(objlist),

這種binding不到的狀況你的model需要運用?運算子讓他可以是null
就能避免你說接不到的問題
例如

public class test
{
    public int? a {get;set;}
}

目前接資料的方式但不知道如何對映到我的dto因為變了2層且就算硬轉換顯示也為0

這個不知道model怎麼建
有個簡單的方法就是用JSON選擇性貼上
VS內建的功能
https://ithelp.ithome.com.tw/upload/images/20211210/20109839Hz0T4S2a3h.jpg

看更多先前的回應...收起先前的回應...

Homura大你好,因為我的json是用 {score:[{}]}裡面包array的方式會有2層所以腦袋有點轉不過來要怎麼在拆到下一層讓我可以用強行別的方式讀到scoreID跟scoreVal,現在參數放RootDto的話只會有ob能用但它顯示為0,看f12的console它印出會是Array(0) length: 0。另外model需要運用?運算子讓他可以是null是不是只能套用在int上

   public class RootDTO
    {
        public List<Obj> ob { get; set; }
    }
    public class Obj
    {
        public string selectedEmpValue { get; set; }
        public string scoreId { get; set; }
        public string scoreVal { get; set; }

    }
Homura iT邦高手 1 級 ‧ 2021-12-10 11:16:30 檢舉

shen2255678

現在參數放RootDto的話只會有ob能用但它顯示為0

這樣代表沒接到
你ajax那邊要調整一下
應該不用jsonstringfy才對
改這樣試試看

$.ajax({
                url: 'http://HaoweiLu.com/DnaAPI/api/Values/',
                type: 'POST',
                crossDomain: true,
                cache: false,
                async: false,
                dataType: 'json',
                data: { score: objlist },
            success: function (data) {
                alert('接收成功');
                console.log(data);
            }
        });

另外model需要運用?運算子讓他可以是null是不是只能套用在int上

這個是運用在不能null的形態上喔
List和string是可以null的所以不需要

這個方式我昨天有試過還是會是null,QQ所以我才跑去用Joject。

//目前是改成這樣測試但中間的var objx會變成null無法轉換成RootDTO類別的錯誤發生
 [HttpPost]
    public IHttpActionResult Post([FromBody]Jobject model)
        {

            var a = model.ToString();
            var jObject = JsonConvert.SerializeObject(a);
            var objx = JsonConvert.DeserializeObject<RootDTO>(jObject);
            Model1 db = new Model1();
            hao_message test = new hao_message();
            foreach (Score ep in objx.score)
            {
                test.emp = ep.selectedEmpValue;
                test.dep = ep.scoreId;
                test.score = int.Parse(ep.scoreVal);
                test.header = "測試6";
            }
            return Ok(model);

        }
Homura iT邦高手 1 級 ‧ 2021-12-10 13:06:33 檢舉

shen2255678
會NULL表示設定有問題...
或你資料格式不對
把你完整的Controller和request body貼出來看看

有用JSON.stringify的話F12的網路的FormData會變成以下這些
score: [{"selectedEmpValue":"0528052","scoreId":"34","scoreVal":"1"},{"selectedEmpValue":"0528052","scoreId":"35","scoreVal":"2"}]
用這個方式data: { score: objlist }沒用JSON.stringify的話F12的網路的FormData會變成以下這些
score[0][selectedEmpValue]: 0426052
score[0][scoreId]: 34
score[0][scoreVal]: 1

 public class RootDTO
    {
        public List<Score> score { get; set; }
    }
    public class Score
    {
        public string selectedEmpValue { get; set; }
        public string scoreId { get; set; }
        public string scoreVal { get; set; }

    }

我傳的資料為{"score":[{"selectedEmpValue":"0426052","scoreId":"34","scoreVal":"1"}]}
是用POSTMAN測試的為NULL。

//現在先單純先接資料而已所以先把SAVECHANgE的程式移掉雖然也不能跑
[HttpPost]
        public IHttpActionResult Post([FromBody]List<RootDTO> model)
        {

            return Ok(model);

        }
Homura iT邦高手 1 級 ‧ 2021-12-10 13:49:56 檢舉

shen2255678
幫你測了一下
你這樣當然打不進去
因為你的body裡面第一層就是array...
你的data要長這樣才對

[
{"score":[{"selectedEmpValue":"0426052","scoreId":"34","scoreVal":"1"}]}
]

https://ithelp.ithome.com.tw/upload/images/20211210/20109839H0Q4ULWnrX.jpg

話說api不是有預設swagger當作測試嗎?
怎不用swagger丟資料時開啟F12監聽看看丟什麼資料出去

因為我原本都用Mvc的專案寫api現在改成用webapi專案去寫,所以我也不知道swagger是什麼。不過既然第一層是array我就有點困惑?我只有在orglist哪裡先宣告成[],score:只有在Ajax 中的data那一行才添加。那為何第一層就是array那這樣我Ajax的data要怎樣修改才能讓前端能post正確的資料@@

Homura iT邦高手 1 級 ‧ 2021-12-10 14:31:04 檢舉

shen2255678
data並沒限定array或obj
改下面這樣

$.ajax({
                url: 'http://HaoweiLu.com/DnaAPI/api/Values/',
                type: 'POST',
                crossDomain: true,
                cache: false,
                async: false,
                dataType: 'json',
                data: [ {score: objlist} ],
            success: function (data) {
                alert('接收成功');
                console.log(data);
            }
        });

swagger是一個讓你測試API用的套件
會在執行後開啟網頁進入
可直接在頁面測試API
如果你新開一個API專案預設應該是會幫你裝好

但我剛剛測試我data:[]起始這裡不能放這個括號一定要配{}這個才行。但我現在電腦暫時不能用只能等等再確定一下是不是我看錯。另外我不用json.stringify 的話可以嗎?因為在我前幾樓回答的哪裡不加的情況form body的模樣會有些不同欸

Homura iT邦高手 1 級 ‧ 2021-12-10 15:47:21 檢舉

shen2255678
[from body]你的contentype需要application/x-www-form-urlencoded
如果拿掉要改用application/json就不需要
json.stringify應該還是需要
我剛剛整個測一遍
你的data好像跟model對不起來
我貼我寫的給你試試

    public class ValuesController : ApiController
    {

        [HttpPost]
        public IHttpActionResult PostData( RootDTO model)
        {
            
            return Ok(model);

        }

        public class RootDTO
        {
            public List<Obj> ob { get; set; }
        }
        public class Obj
        {
            public string selectedEmpValue { get; set; }
            public string scoreId { get; set; }
            public string scoreVal { get; set; }

        }
    }

js

    $.ajax({
        url: 'https://localhost:44320/api/Values/',
        type: 'POST',
        crossDomain: true,
        cache: false,
        async: false,
        dataType: 'json',
        contentType:'application/json',
        data: JSON.stringify({ ob: [{ "selectedEmpValue": "0426052", "scoreId": "34", "scoreVal": "1" }] })
        ,
        success: function (data) {
            console.log('接收成功');
            console.log(data);
        }

Homura iT邦高手 1 級 ‧ 2021-12-10 15:51:33 檢舉

你原始的寫法應該是要這樣丟

    $.ajax({
        url: 'https://localhost:44320/api/Values/',
        type: 'POST',
        crossDomain: true,
        cache: false,
        async: false,
        dataType: 'json',
        contentType:'application/json',
        data: JSON.stringify([{ "selectedEmpValue": "0426052", "scoreId": "34", "scoreVal": "1" } ])
        ,
        success: function (data) {
            console.log('接收成功');
            console.log(data);
        }
    });

用上述的方式會沒辦法post過去,不過我終於知道為何我會出現錯誤跟我幹嘛改掉原始的寫法因為我加了
contentType:'application/json'我的f12的網路就會跑出CORS Error的status沒辦法傳到後端才把contentType:'application/json'去掉。因為好像是
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status這個的關係?

Homura iT邦高手 1 級 ‧ 2021-12-10 16:22:01 檢舉

shen2255678
你有CORS需要把api的cores設定解開
並把web加入白名單才行
https://stackoverflow.com/questions/18619656/enable-cors-in-web-api-2

恩恩我剛剛就先把前端也架在我的網域底下就好了原本想說先測試先不架起來。但目前還是不知道為何我ajax的資料為何對不上去就是會少[]包起來。目前暫時的解法就是繼續用以前的方式去寫不要多一層ROOTDTO因為知道是CORS ERROR的STATUS的導致的關係。感謝Homura大大我假日在想想要如何對映

1
japhenchen
iT邦超人 1 級 ‧ 2021-12-10 10:18:24

我用 Newtonsoft.Json;

using Newtonsoft.Json;


protected void Page_Load(object sender, EventArgs e)
{
    var jsonstr = Request.Form["jsonPost"]
    var objx = JsonConvert.DeserializeObject<RootDTO>(jsonstr);
    foreach(var item in objx){
        // ... you kbown ..
    }
}
看更多先前的回應...收起先前的回應...

nuget上就有 newtonsoft.json 可用,授權沒限制商用環境

japhenchen大,但因為我這樣有2層這樣用的話會變成只有item.ob能使用,而且因為有objx會有錯誤的提示字不包含 getenumerator的功用執行定義不能使用foreach

public IHttpActionResult Post([FromBody]JObject model)
        {

             var a = model.ToString();
        var objx = JsonConvert.DeserializeObject<RootDTO>(a);
            try
            {
                Model1 db = new Model1();

                hao_message test = new hao_message();
                for(int i = 0; i < 2; i++)
                {
                    
                }
                foreach (var item in objx)
                {
                    test.emp = item.selectedEmpValue;
                    test.dep = item.scoreId;
                    test.score = int.Parse(item.scoreVal);
                    test.header = "測試3";

                    db.hao_message.Add(test);
                    db.SaveChanges();
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
  //我有想說先用jtoken拆一層出來在用對映OBJ class試試看但會有錯誤的提示字不包含 getenumerator的功用執行定義不能使用foreach可能因為JsonConvert.DeserializeObject<T>它不能前面多加list<T>的形式?
   JToken jToken = model["score"];
    var a = jToken.ToString();
    var objx = JsonConvert.DeserializeObject<Obj>(a);

想知道你送出來的json原型是什麼,如果你要用

List<List<String>>

的話,只要你的json內容是[[]]就不是問題

我的json是 {[{},...]}這樣包起來用jobect的話console印出來會是
{ "score": "[{\"selectedEmpValue\":\"0426052\",\"scoreId\":\"34\",\"scoreVal\":\"2\"},{\"selectedEmpValue\":\"0426052\",\"scoreId\":\"35\",\"scoreVal\":\"1\"}]" } __proto__: Object

{[ 裡面包 { 則要用
class {
List<T>
}

是我文章一開始RootDTO這樣的形式嗎?

public class RootDTO
    {
        public List<Obj> ob { get; set; }
    }
    public class Obj
    {
        public string selectedEmpValue { get; set; }
        public string scoreId { get; set; }
        public string scoreVal { get; set; }

    }

我後來有稍微測試一下類似的寫法但還是無法因為中間的var objx會變成null無法轉換成RootDTO類別的錯誤發生

[HttpPost]
    public IHttpActionResult Post([FromBody]Jobject model)
     {

         var a = model.ToString();
         var jObject = JsonConvert.SerializeObject(a);
         var objx = JsonConvert.DeserializeObject<RootDTO>(jObject);
            Model1 db = new Model1();
            hao_message test = new hao_message();
            foreach (Obj ep in objx.ob)
            {
                test.emp = ep.selectedEmpValue;
                test.dep = ep.scoreId;
                test.score = int.Parse(ep.scoreVal);
                test.header = "測試6";
            }
            return Ok(model);

        }

那建議你用循環的方式去新增

List<RTO> nlist = new List<RTO>();
foreach(var item in objx){
    if(item!=null)
        nlist.Add(item);
        
}

我要發表回答

立即登入回答