为什么我与竞争的Newtonshoft.Json.Linq。[JArray,JObject]得到一个InvalidCastException,代码/数据非常相似?

时间:2014-01-21 00:48:29

标签: rest httpwebrequest json.net streamreader httpwebresponse

此代码正常工作 - 返回与REST查询匹配的单个记录:

Popul8TheGrid("http://localhost:28642/api/subdepartments/1/10");

private void Popul8TheGrid(string URIToPass)
{
    try
    {
        dataGridView1.DataSource = GetRESTData(URIToPass);
    }
    catch (WebException webex)
    {
        MessageBox.Show("Eek, a mousey-pooh! ({0})", webex.Message);
    }
}

private JArray GetRESTData(string uri)
{
    var webRequest = (HttpWebRequest) WebRequest.Create(uri);
    var webResponse = (HttpWebResponse) webRequest.GetResponse();
    var reader = new StreamReader(webResponse.GetResponseStream());
    string s = reader.ReadToEnd();
    return JsonConvert.DeserializeObject<JArray>(s);
}

但是,这段代码也应该返回一条记录:

private const string BASE_URI = "http://localhost:28642/api/";
. . .
string URIToPass = string.Format("{0}deliveryitems/{1}", BASE_URI, numericUpDownDeliveryItemId.Value);
Popul8TheGrid(URIToPass);

...失败,“ InvalidCastException未处理... Message =无法将类型为'Newtonsoft.Json.Linq.JObject'的对象强制转换为'Newtonsoft.Json.Linq.JArray'”。

为什么会这样?从第一个(工作)片段返回的数据来自MS Access“数据库”

来自第二个(失败的)片段的数据来自测试数据:

public DeliveryItemRepository() 
{
    // Just some bogus/test data for now
    Add(new DeliveryItem
    {
        Id = 1, InvoiceNumber = "123", UPC_PLU = "456", VendorItemId = "789", PackSize = 1, Description = "Something", Quantity = 5, Cost = 1.25M, 
        Margin = 0.25M, ListPrice = 1.50M, DepartmentNumber = 42, Subdepartment = "5"
    });

。 。

这是Controller方法;在浏览器中输入URI时,它可以正常工作。

// Enter "http://localhost:28642/api/1"
[Route("api/DeliveryItems/{ID:int}")] 
public DeliveryItem GetDeliveryItemById(int ID)
{
    return _deliveryItemRepository.GetById(ID);
}

......但为什么那会很重要,我不知道......

更新

有趣的是(也许我很容易被逗乐),这个,OTOH,有效:

MessageBox.Show(GetRESTScalarVal("http://localhost:28642/api/deliveries/1"));
. . .
private string GetRESTScalarVal(string uri)
{
    var client = new WebClient();
    return client.DownloadString(uri);
}

通过“工作”,我的意思是它返回:

enter image description here

所以DownloadString()甚至会返回一个完整的json“记录”,而我对“Scalar”这个词的使用会产生误导。也许我应该说“单一”,虽然这也可能令人困惑,同样的称谓的数据类型是什么。

关于如何使用单个json“记录”填充数据网格仍然存在问题

更新2

奇怪的是,如果我使用不同的Controller方法来获取一条记录,它就会起作用:

private void GetDeliveryItemById()
{
    //string uri = string.Format("deliveryitems/{0}", numericUpDownId.Value);
    string uri = string.Format("deliveryitems/{0}/1", numericUpDownId.Value);
    Popul8TheGrid(uri);
}

注释掉的代码是爆炸的,而另一个,提供的const值为1,工作... kludgy,但它有效。

更新3

这个存储库代码可能是一个线索/与为什么它在获取它时不起作用有关,但另有效果的是:

public SiteMapping GetById(int ID)
{
    return siteMappings.Find(p => p.Id == ID);
}

public IEnumerable<SiteMapping> GetRange(int ID, int CountToFetch)
{
    return siteMappings.Where(i => i.Id >= ID).Take(CountToFetch);
}

如果使用存在的ID调用GetById(),它会起作用;但是,如果传递了一个不存在的,则失败,“用户代码未处理InvalidOperationException ... ... Message = Sequence不包含匹配的元素”

调用GetRange()可以很有效地工作 - 如果传递了一对虚假的vals(没有记录),它只是耸了耸肩,而不是让那个老式的眼睛疯狂地尖叫着。

将其更改为(参见Simon Whitehead的回答here)有效:

public SiteMapping GetById(int ID)
{
    var entity = siteMappings.Find(p => p.Id == ID);
    return entity == null ? null : entity;
}

因此,尝试通过特定ID找到是脆弱的;试图通过ID + Count找到工作得很好。为什么,我(仍然)不知道...

1 个答案:

答案 0 :(得分:0)

这可能有点笨拙,但它有效:

private JArray GetRESTData(string uri)
{
    try
    {
        var webRequest = (HttpWebRequest)WebRequest.Create(uri);
        var webResponse = (HttpWebResponse)webRequest.GetResponse();
        var reader = new StreamReader(webResponse.GetResponseStream());
        string s = reader.ReadToEnd();
        return JsonConvert.DeserializeObject<JArray>(s);
    }
    catch // This method crashes if only one json "record" is found - try this:
    {
        try
        {
            MessageBox.Show(GetScalarVal(uri));
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
    return null;
}

private string GetScalarVal(string uri)
{
    var client = new WebClient();
    return client.DownloadString(uri);
}