Json 响应未在视图中输出,而是提示我下载文件
我正在使用 WebRequest 从 FCC 读取 JSON 数据,以便可以将其输出到视图。这是我用于持有 FCC 许可证的自定义类:
public class License
{
public string Name{ get; set; }
public string Frn { get; set; }
public string Callsign { get; set;}
public string CategoryDesc { get; set; }
public string ServiceDesc { get; set; }
public string StatusDesc { get; set; }
public DateTime ExpiredDate { get; set; }
public string Id { get; set; }
public string DetailUrl { get; set; }
}
这是我用来读取 json 结果的控制器操作。
我现在将 Verizon Wireless 硬编码为搜索值:
public ActionResult GetLicenses()
{
var result = string.Empty;
var url = "http://data.fcc.gov/api/license-view/basicSearch/getLicenses?searchValue=Verizon+Wireless&format=jsonp&jsonCallback=?";
var webRequest = WebRequest.Create(url);
webRequest.Timeout = 2000;
using (var response = webRequest.GetResponse() as HttpWebResponse)
{
if (response.StatusCode == HttpStatusCode.OK)
{
var receiveStream = response.GetResponseStream();
if (receiveStream != null)
{
var stream = new StreamReader(receiveStream);
result = stream.ReadToEnd();
}
}
}
return new ContentResult { Content = result, ContentType = "application/json" };
}
这是视图。我试图枚举所有许可证并将它们输出到表中,但是当我转到 /Home/GetLicenses 时,它提示我下载文件:
@model IEnumerable<MvcApplication1.Models.License>
@{
ViewBag.Title = "Licenses";
}
<h2>Licenses</h2>
<table>
<tr>
<th>
Name
</th>
<th>
Frn
</th>
<th>
Callsign
</th>
<th>
CategoryDesc
</th>
<th>
ServiceDesc
</th>
<th>
StatusDesc
</th>
<th>
ExpiredDate
</th>
<th>
DetailUrl
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Frn)
</td>
<td>
@Html.DisplayFor(modelItem => item.Callsign)
</td>
<td>
@Html.DisplayFor(modelItem => item.CategoryDesc)
</td>
<td>
@Html.DisplayFor(modelItem => item.ServiceDesc)
</td>
<td>
@Html.DisplayFor(modelItem => item.StatusDesc)
</td>
<td>
@Html.DisplayFor(modelItem => item.ExpiredDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.DetailUrl)
</td>
</tr>
}
</table>
如果我直接通过 jquery 的 getJSON 方法执行上述操作,则可以得到上述工作,但是我想看看是否可以将结果从控制器获取到视图,然后将其呈现在视图中。
这是结果变量中返回内容的示例:
?({
"status": "OK",
"Licenses": {
"page": "1",
"rowPerPage": "100",
"totalRows": "1995",
"lastUpdate": "Sep 21, 2011",
"License": [
{
"licName": "CELLCO PARTNERSHIP (\"VERIZON WIRELESS\")",
"frn": "",
"callsign": "",
"categoryDesc": "Satellite Earth Station",
"serviceDesc": "",
"statusDesc": "Active",
"expiredDate": "",
"licenseID": "2300007967",
"licDetailURL": "http://licensing.fcc.gov/cgi-bin/ws.exe/prod/ib/forms/reports/swr031b.hts?prepare=&column=V_SITE_ANTENNA_FREQ.file_numberC/File+Number&q_set=V_SITE_ANTENNA_FREQ.file_numberC/File+Number/=/FCNNEW2000060800036"
},
{
"licName": "CELLO PARTNERSHIP (\"VERIZON WIRELESS\")",
"frn": "",
"callsign": "",
"categoryDesc": "Satellite Earth Station",
"serviceDesc": "",
"statusDesc": "Active",
"expiredDate": "",
"licenseID": "2300010661",
"licDetailURL": "http://licensing.fcc.gov/cgi-bin/ws.exe/prod/ib/forms/reports/swr031b.hts?prepare=&column=V_SITE_ANTENNA_FREQ.file_numberC/File+Number&q_set=V_SITE_ANTENNA_FREQ.file_numberC/File+Number/=/FCNNEW2000083100048"
},
{
"licName": "Cellco Partnership d/b/a Verizon Wireless",
"frn": "0003290673",
"callsign": "KE2XMC",
"categoryDesc": "Experimental",
"serviceDesc": "Experimental Developmental",
"statusDesc": "Unknown",
"expiredDate": "12/14/2000",
"licenseID": "3000020853",
"licDetailURL": "https://fjallfoss.fcc.gov/oetcf/els/reports/ELSSearchResult.cfm?callsign=KE2XMC"
},
{
"licName": "Cellco Partnership d/b/a Verizon Wireless",
"frn": "0003290673",
"callsign": "WA2XPS",
"categoryDesc": "Experimental",
"serviceDesc": "Experimental Developmental",
"statusDesc": "Unknown",
"expiredDate": "12/14/2000",
"licenseID": "3000020851",
"licDetailURL": "https://fjallfoss.fcc.gov/oetcf/els/reports/ELSSearchResult.cfm?callsign=WA2XPS"
},
{
"licName": "Cellco Partnership dba Verizon Wireless",
"frn": "0003290673",
"callsign": "KNKP866",
"categoryDesc": "Mobile/Fixed Broadband",
"serviceDesc": "Cellular",
"statusDesc": "Cancelled",
"expiredDate": "10/01/2005",
"licenseID": "13328",
"licDetailURL": "http://wireless2.fcc.gov/UlsApp/UlsSearch/license.jsp?__newWindow=false&licKey=13328"
}
]
}
})
我添加了此类:
public class FCC
{
public string status { get; set; }
public Licenses Licenses { get; set; }
}
但我仍然得到无效的 JSON 原语。
public ActionResult GetLicenses()
{
var result = string.Empty;
var url =
"http://data.fcc.gov/api/license-view/basicSearch/getLicenses?searchValue=Verizon+Wireless&format=jsonp&jsonCallback=?";
var webRequest = WebRequest.Create(url);
webRequest.Timeout = 2000;
webRequest.ContentType = "application/json";
using (var response = webRequest.GetResponse() as HttpWebResponse)
{
if (response.StatusCode == HttpStatusCode.OK)
{
var receiveStream = response.GetResponseStream();
if (receiveStream != null)
{
var stream = new StreamReader(receiveStream);
result = stream.ReadToEnd();
}
}
}
FCC fcc = new FCC();
if (result.StartsWith(@"?("))
{
result = result.Substring(2);
}
if (result.EndsWith(@")"))
{
result = result.Remove(result.Length - 1);
}
if (result != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
fcc = serializer.Deserialize<FCC>(result);
}
return View(fcc.Licenses.License);
}
I am using WebRequest to read JSON data from the FCC so I can output it to a view. Here is my custom class to hold an FCC license:
public class License
{
public string Name{ get; set; }
public string Frn { get; set; }
public string Callsign { get; set;}
public string CategoryDesc { get; set; }
public string ServiceDesc { get; set; }
public string StatusDesc { get; set; }
public DateTime ExpiredDate { get; set; }
public string Id { get; set; }
public string DetailUrl { get; set; }
}
Here is the Controller action that I am using to read the json results.
I have Verizon Wireless hard-coded as the search value for now:
public ActionResult GetLicenses()
{
var result = string.Empty;
var url = "http://data.fcc.gov/api/license-view/basicSearch/getLicenses?searchValue=Verizon+Wireless&format=jsonp&jsonCallback=?";
var webRequest = WebRequest.Create(url);
webRequest.Timeout = 2000;
using (var response = webRequest.GetResponse() as HttpWebResponse)
{
if (response.StatusCode == HttpStatusCode.OK)
{
var receiveStream = response.GetResponseStream();
if (receiveStream != null)
{
var stream = new StreamReader(receiveStream);
result = stream.ReadToEnd();
}
}
}
return new ContentResult { Content = result, ContentType = "application/json" };
}
Here is the view. I am trying to enumerate through all the licenses and output them to a table, but when I go to /Home/GetLicenses, it prompts me to download the file:
@model IEnumerable<MvcApplication1.Models.License>
@{
ViewBag.Title = "Licenses";
}
<h2>Licenses</h2>
<table>
<tr>
<th>
Name
</th>
<th>
Frn
</th>
<th>
Callsign
</th>
<th>
CategoryDesc
</th>
<th>
ServiceDesc
</th>
<th>
StatusDesc
</th>
<th>
ExpiredDate
</th>
<th>
DetailUrl
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Frn)
</td>
<td>
@Html.DisplayFor(modelItem => item.Callsign)
</td>
<td>
@Html.DisplayFor(modelItem => item.CategoryDesc)
</td>
<td>
@Html.DisplayFor(modelItem => item.ServiceDesc)
</td>
<td>
@Html.DisplayFor(modelItem => item.StatusDesc)
</td>
<td>
@Html.DisplayFor(modelItem => item.ExpiredDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.DetailUrl)
</td>
</tr>
}
</table>
I got the above working if I do it directly through jquery's getJSON method, but I wanted to see if I could get the results from a contoller to a view and then have it rendered in the view.
This is a sample of what is returned in the results variable:
?({
"status": "OK",
"Licenses": {
"page": "1",
"rowPerPage": "100",
"totalRows": "1995",
"lastUpdate": "Sep 21, 2011",
"License": [
{
"licName": "CELLCO PARTNERSHIP (\"VERIZON WIRELESS\")",
"frn": "",
"callsign": "",
"categoryDesc": "Satellite Earth Station",
"serviceDesc": "",
"statusDesc": "Active",
"expiredDate": "",
"licenseID": "2300007967",
"licDetailURL": "http://licensing.fcc.gov/cgi-bin/ws.exe/prod/ib/forms/reports/swr031b.hts?prepare=&column=V_SITE_ANTENNA_FREQ.file_numberC/File+Number&q_set=V_SITE_ANTENNA_FREQ.file_numberC/File+Number/=/FCNNEW2000060800036"
},
{
"licName": "CELLO PARTNERSHIP (\"VERIZON WIRELESS\")",
"frn": "",
"callsign": "",
"categoryDesc": "Satellite Earth Station",
"serviceDesc": "",
"statusDesc": "Active",
"expiredDate": "",
"licenseID": "2300010661",
"licDetailURL": "http://licensing.fcc.gov/cgi-bin/ws.exe/prod/ib/forms/reports/swr031b.hts?prepare=&column=V_SITE_ANTENNA_FREQ.file_numberC/File+Number&q_set=V_SITE_ANTENNA_FREQ.file_numberC/File+Number/=/FCNNEW2000083100048"
},
{
"licName": "Cellco Partnership d/b/a Verizon Wireless",
"frn": "0003290673",
"callsign": "KE2XMC",
"categoryDesc": "Experimental",
"serviceDesc": "Experimental Developmental",
"statusDesc": "Unknown",
"expiredDate": "12/14/2000",
"licenseID": "3000020853",
"licDetailURL": "https://fjallfoss.fcc.gov/oetcf/els/reports/ELSSearchResult.cfm?callsign=KE2XMC"
},
{
"licName": "Cellco Partnership d/b/a Verizon Wireless",
"frn": "0003290673",
"callsign": "WA2XPS",
"categoryDesc": "Experimental",
"serviceDesc": "Experimental Developmental",
"statusDesc": "Unknown",
"expiredDate": "12/14/2000",
"licenseID": "3000020851",
"licDetailURL": "https://fjallfoss.fcc.gov/oetcf/els/reports/ELSSearchResult.cfm?callsign=WA2XPS"
},
{
"licName": "Cellco Partnership dba Verizon Wireless",
"frn": "0003290673",
"callsign": "KNKP866",
"categoryDesc": "Mobile/Fixed Broadband",
"serviceDesc": "Cellular",
"statusDesc": "Cancelled",
"expiredDate": "10/01/2005",
"licenseID": "13328",
"licDetailURL": "http://wireless2.fcc.gov/UlsApp/UlsSearch/license.jsp?__newWindow=false&licKey=13328"
}
]
}
})
I added this class:
public class FCC
{
public string status { get; set; }
public Licenses Licenses { get; set; }
}
But I still get the Invalid JSON primitive.
public ActionResult GetLicenses()
{
var result = string.Empty;
var url =
"http://data.fcc.gov/api/license-view/basicSearch/getLicenses?searchValue=Verizon+Wireless&format=jsonp&jsonCallback=?";
var webRequest = WebRequest.Create(url);
webRequest.Timeout = 2000;
webRequest.ContentType = "application/json";
using (var response = webRequest.GetResponse() as HttpWebResponse)
{
if (response.StatusCode == HttpStatusCode.OK)
{
var receiveStream = response.GetResponseStream();
if (receiveStream != null)
{
var stream = new StreamReader(receiveStream);
result = stream.ReadToEnd();
}
}
}
FCC fcc = new FCC();
if (result.StartsWith(@"?("))
{
result = result.Substring(2);
}
if (result.EndsWith(@")"))
{
result = result.Remove(result.Length - 1);
}
if (result != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
fcc = serializer.Deserialize<FCC>(result);
}
return View(fcc.Licenses.License);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
通过从 ActionMethod 返回
ContentResult
,您的浏览器将根据内容以适当的操作进行响应。在这种情况下,将像文件一样下载 JSON 字符串,因为它不是 HTML 文档。如果您想在视图中呈现结果而不是通过 AJAX,那么您需要创建一个表示 WebRequest 响应数据的 C# 模型类,然后返回一个
ViewResult
并传递模型(或集合)模型)到视图。我建议更改您的
ActionMethod
来执行如下所示的操作,并创建一个名为“Licenses”的视图此外,您的示例响应有点诡计。它比原始许可证对象的数组更复杂,并且它用
?()
包装。 JavaScriptSerializer 将仅反序列化它可以根据属性名称匹配的属性(也区分大小写)。由于?()
包装,我们需要将其删除,这样反序列化就不会中断。因此,您需要相应地修改您的许可证对象:
最后,您将需要更改 CSHTML 文件中的属性名称,因为新的许可证对象不再具有相同的属性名称。
AJAX 可能是另一个问题,但如果我遇到一个很好的例子,我会在这里发帖
By returning a
ContentResult
from your ActionMethod, your browser is going to respond with the appropriate action based upon the content. In this case a JSON string will be downloaded similar to a file since it is not a HTML doc.If you want to render the results in a View and not through AJAX, then you will need to create a C# Model class representing your WebRequest response data, and then return a
ViewResult
and pass the model (or collection of models) to the View.I would suggest changing your
ActionMethod
to do something like below, and also create a View called "Licenses"Also, your example response is a bit of a trick. It is more complex than an array of your original License Object, AND it is wrapped with a
?()
. The JavaScriptSerializer will only deserialize properties that it can match based on property name (it is case sensitive as well). And because of the?()
wrapping, we need to remove that so the deserialization won't break.So you would need to modify your License object accordingly:
Lastly, you will need to change the property names in your CSHTML file, since the new License object doesn't have the same property names anymore.
AJAX is probably another question, but I'll post back here if I run across a good example
我将尝试解决您的代码中的几个问题:
因此,让我们从视图模型开始:
然后我们将拥有以下控制器:
请注意,我在 url 中不再指定旨在与 JSONP 一起使用的
jsonCallback
查询字符串参数,但我不这样做想要 JSONP,我想要 JSON。为此,我还设置了format=json
参数。最后,我们可以拥有以下
~/Views/Home/Index.cshtml
视图:以及将为 Licenses 集合的每个元素呈现的相应显示模板 (
~/Views/Home /DisplayTemplates/License.cshtml
):好的,到目前为止我们已经有了地址点 1 和 2。
现在是第三个。此同步调用的问题在于以下行:
client.DownloadString
。这是一个阻塞调用。在 ASP.NET 应用程序中,阻止对远程资源的调用非常糟糕。在这里,您正在获取一些远程资源,这可能需要时间=>您将穿越网络边界、互联网防火墙……直到您到达远程 Web 服务器,该服务器本身为了满足请求将查询数据库……您明白了:它很慢。在这段时间里,您的 Web 应用程序一直处于等待状态,并且线程被垄断。请记住,您可以使用的工作线程数量有限,因此不要浪费它们。解决这个非常严重的问题的方法是使用异步控制器和 I/O 完成端口。它们直接内置于 Windows 内核中,允许您执行 IO 密集型操作,而无需阻塞和独占服务器上的线程。
您的 HomeController 将变成以下样子:
There are a couple of issues with your code which I will try to address:
So let's start by our view models:
then we would have the following controller:
Notice how in the url I am no longer specifying the
jsonCallback
querystring parameter which is intended to be used with JSONP and I don't want JSONP, I want JSON. For that matter I have also set theformat=json
parameter.And finally we could have the following
~/Views/Home/Index.cshtml
view:and the corresponding display template which will be rendered for each element of the Licenses collection (
~/Views/Home/DisplayTemplates/License.cshtml
):OK, so far we have addresses point 1. and 2.
Now the third one. The problem with this synchronous call is the following line:
client.DownloadString
. This is a blocking call. Blocking calls on remote resources are very bad in ASP.NET applications. Here you are fetching some remote resource which could take time => you will be traversing network boundaries, internet firewalls, ... until you hit the remote web server which itself, in order to serve the request will query a database, ... You get the point: it is slow. And during all this time your web application is sitting and waiting and a thread was monopolized. Remember that you have a limited number of worker threads at your disposal so don't waste them.The way to solve this very serious issue is to use asynchronous controllers and I/O Completion Ports. Those are built directly into windows kernel and allow you to perform IO intensive operations without blocking and monopolizing threads on your server.
Here's how your HomeController will become:
这是我所做的,它在 DIV 中向我显示 Json 数据...
您的控制器...
在 Action 中设置返回类型 Json 并输入 JsonResult
,如果您想通过 AJAX 调用它,那么这里是
$.ajax
并确保您在 _Layout.cshtml 中引用 Jquery 文件。
Here is what i did and its showing me Json data in DIV...
Your Controller...
make the return type Json and type JsonResult in Action
and if you want to call this through AJAX then here is the
$.ajax
and make sure that you reference the Jquery files in _Layout.cshtml..