Web API 2无法读取通过Retrofit 2发送的byte []

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web API 2无法读取通过Retrofit 2发送的byte []相关的知识,希望对你有一定的参考价值。

我正在尝试使用Retrofit 2和Web API 2将客户端sq-lite数据库中的对象上传到MSSQL。

如果我将nullnew byte[1000]分配给访问,该应用程序没有任何问题。图像,但每当从sq-lite数据库检索其指定值时,我得到错误响应代码400

{
  "Message": "The request is invalid.",
  "ModelState": {
    "visit.Image[0]": [
      "An error has occurred."
    ],
    "visit.Image[1]": [
      "An error has occurred."
    ]
  }
}

这是我在android中的模型:

public class Visit {
    public int VisitId;
    public String DealerMId;
    public byte[] Image; // read image from database (blob data type)
}

这是我从数据库中检索值并创建Visit对象的代码

public Visit getVisitByVisitId(long visitId) {
        SQLiteDatabase db = this.getReadableDatabase();

        String selectQuery = "SELECT  * FROM " + TABLE_VISIT + " WHERE "
                + KEY_ID + " = " + visitId;
        Cursor c = db.rawQuery(selectQuery, null);

        if (c != null)
            c.moveToFirst();

        Visit visit = new Visit();

        visit.VisitId = c.getInt(c.getColumnIndex(KEY_ID));
        visit.DealerMId = c.getString(c.getColumnIndex(KEY_DEALER_MID));
        visit.Image= c.getBlob(c.getColumnIndex(KEY_PICTURE));

        return visit ;
    }

这是改装服务的使用界面:

@POST("visits/PostVisit")
public Call<Integer> postVisit(@Body Visit visit);

这是活动代码:

Visit vistit = db.getVisitById(1) ;

// Note that : every thing working fine 
// if visit.Image = null or visit.Image = new byte[1000] or visit.Image = new byte[]{1,4,3 ..}
// but I am receiving error 400 when visit.Image contains value from database

Call<Integer> call = RetrofitService.postVisit(visit);    

call.enqueue(new Callback<Integer>() {
          @Override
          public void onResponse(Call<Integer> call, Response<Integer>response){
                    //....
            }
          @Override
          public void onFailure(Call<Integer> call, Throwable t) {
                    //....
            }
});

而这个Web API 2代码

[HttpPost]
public IHttpActionResult PostVisit(Visit visit)
{

    if (!ModelState.IsValid)
    {
         return BadRequest(ModelState);
    }

    db.Visits.Add(visit);

    try
    {
        db.SaveChanges();
    }
    catch (DbUpdateException)
    {
        if (VisitExists(visit.VisitId))
        {
            return Ok(-1);
        }
        else
        {
            throw;
        }
    }
    return Ok(visit.VisitId);
}

android studio的以下屏幕截图显示了Visit.Image的检索内容,我确信它自己的内容没有问题,因为我可以在ImageView的Android应用程序中读取它。

This is a screen shot from android studio taken when I was debugging the code, it shows the Visit.Image value which is retrieved from the database

答案

好吧,您要将字节从Java发布到C#。问题是Java字节的范围在-128到127之间,而C#字节的范围是0到255.当你从Java发布字节时,它们被序列化为JSON字符串([' - 128',' - 30','127'])您的WebApi控制器接收它们并尝试将它们反序列化为C#字节(范围从0到255)。不幸的是,它由于负数而失败。所以你必须正确地反序列化。


Option 1: Use sbyte in conroller.

在Web Api中,将模型更改为:

public class Visit 
{
    public int VisitId;
    public String DealerMId;
    public sbyte[] Image; // only for C#
}

WebApi控制器将数组成功反序列化为sbyte(范围:-128到127),然后您可以轻松地将它们转换为字节(取自SO answer):

byte[] imageBytes = (byte[]) (Array)myVisitModel.Image; 

Option 2: Send int[] from Java

将您的字节发送为int [],以便发送0到255之间的字节。

Change your model in Java to:

public class Visit {
    public int VisitId;
    public String DealerMId;
    public int[] Image;
}

Convert byte[] into int[]:

byte[] imageBytes = c.getBlob(c.getColumnIndex(KEY_PICTURE));
visit.Image= convertToIntArray(imageBytes);

Convert method (taken from Jon Skeet's answer):

public static int[] convertToIntArray(byte[] input)
{
    int[] ret = new int[input.length];
    for (int i = 0; i < input.length; i++)
    {
        ret[i] = input[i] & 0xff; // Range 0 to 255, not -128 to 127
    }
    return ret;
}

注意:我建议第一个选项,它将在服务器端完成,而第二个选项可能需要很长时间才能转换为客户端的int[]

另一答案

你可以使用JsonSerializer(用Kotlin编写):

class ByteArrayJsonSerializer : JsonSerializer<ByteArray> {

    override fun serialize(src: ByteArray?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
        val intArray = JsonArray()
        src?.forEach { intArray.add(it.toInt() + 128) }
        return intArray
    }
}

并添加到你的Gson:

GsonBuilder()
            .registerTypeAdapter(ByteArray::class.java, ByteArrayJsonSerializer())  // to convert java Byte to C# Byte
            .create()

以上是关于Web API 2无法读取通过Retrofit 2发送的byte []的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的应用程序无法从我的 API 读取 JSON?

C# 无法读取和解释 Web API/JSON

无法使用retrofit2解析api

如何使用 Retrofit 2 + OkHttp 3 加密/隐藏 HTTPS 调用的主体?

如何使用 Retrofit 和 Jackson 读取嵌套的 JSON 数组?

Npm 安装期间“无法读取未定义的属性‘匹配’”