Json 响应未在视图中输出,而是提示我下载文件

发布于 2024-12-05 23:13:23 字数 8068 浏览 0 评论 0原文

我正在使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

诗酒趁年少 2024-12-12 23:13:23

通过从 ActionMethod 返回 ContentResult,您的浏览器将根据内容以适当的操作进行响应。在这种情况下,将像文件一样下载 JSON 字符串,因为它不是 HTML 文档。

如果您想在视图中呈现结果而不是通过 AJAX,那么您需要创建一个表示 WebRequest 响应数据的 C# 模型类,然后返回一个 ViewResult 并传递模型(或集合)模型)到视图。

我建议更改您的 ActionMethod 来执行如下所示的操作,并创建一个名为“Licenses”的视图

此外,您的示例响应有点诡计。它比原始许可证对象的数组更复杂,并且它用 ?() 包装。 JavaScriptSerializer 将仅反序列化它可以根据属性名称匹配的属性(也区分大小写)。由于 ?() 包装,我们需要将其删除,这样反序列化就不会中断。

因此,您需要相应地修改您的许可证对象:

public class FCC
{
    public string status {get;set;}
    public Licenses Licenses {get; set;}
}
public class License
{
    public string licName{ 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 string expiredDate { get; set; } //JSON dates and C# Dates are very finicky
    public string licenseID { get; set; }
    public string licDetailURL { get; set; }
}

public class Licenses
{
    public int page {get; set;}
    public int rowPerPage {get; set;}
    public int totalRows {get; set;}
    public string lastUpdate {get; set;}
    public List<License> License {get; set;}
}


public ActionResult Licenses()
{
        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();
                }
            }
        }

        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); //pass the data that your view needs

}

最后,您将需要更改 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:

public class FCC
{
    public string status {get;set;}
    public Licenses Licenses {get; set;}
}
public class License
{
    public string licName{ 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 string expiredDate { get; set; } //JSON dates and C# Dates are very finicky
    public string licenseID { get; set; }
    public string licDetailURL { get; set; }
}

public class Licenses
{
    public int page {get; set;}
    public int rowPerPage {get; set;}
    public int totalRows {get; set;}
    public string lastUpdate {get; set;}
    public List<License> License {get; set;}
}


public ActionResult Licenses()
{
        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();
                }
            }
        }

        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); //pass the data that your view needs

}

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

酒与心事 2024-12-12 23:13:23

我将尝试解决您的代码中的几个问题:

  1. 您有一个返回 JSON 字符串的控制器操作,并且您已经定义了一些 Razor 视图,但该 razor 视图永远不会从该操作中调用。
  2. 您正在查询返回 JSONP 的远程服务,而不是使用似乎更适合的 API 的 JSON 可能性。
  3. 在获取远程资源期间,您会危及工作线程。

因此,让我们从视图模型开始:

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; }
}

public class Licenses
{
    public License[] License { get; set; }
}

public class FCC
{
    public string status { get; set; }
    public Licenses Licenses { get; set; }
}

然后我们将拥有以下控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        using (var client = new WebClient())
        {
            var json = client.DownloadString("http://data.fcc.gov/api/license-view/basicSearch/getLicenses?searchValue=Verizon+Wireless&format=json");
            var serializer = new JavaScriptSerializer();
            var model = serializer.Deserialize<FCC>(json);
            return View(model.Licenses.License);
        }
    }
}

请注意,我在 url 中不再指定旨在与 JSONP 一起使用的 jsonCallback 查询字符串参数,但我不这样做想要 JSONP,我想要 JSON。为此,我还设置了 format=json 参数。

最后,我们可以拥有以下 ~/Views/Home/Index.cshtml 视图:

@model IEnumerable<License>

<table>
    <thead>
        <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>
    </thead>
    <tbody>
        @Html.DisplayForModel()
    </tbody>
</table>

以及将为 Licenses 集合的每个元素呈现的相应显示模板 (~/Views/Home /DisplayTemplates/License.cshtml):

@model License

<tr>
    <td>
        @Html.DisplayFor(x => x.Name)
    </td>
    <td>
        @Html.DisplayFor(x => x.Frn)
    </td>
    <td>
        @Html.DisplayFor(x => x.Callsign)
    </td>
    <td>
        @Html.DisplayFor(x => x.CategoryDesc)
    </td>
    <td>
        @Html.DisplayFor(x => x.ServiceDesc)
    </td>
    <td>
        @Html.DisplayFor(x => x.StatusDesc)
    </td>
    <td>
        @Html.DisplayFor(x => x.ExpiredDate)
    </td>
    <td>
        @Html.DisplayFor(x => x.DetailUrl)
    </td>
</tr>

好的,到目前为止我们已经有了地址点 1 和 2。

现在是第三个。此同步调用的问题在于以下行:client.DownloadString。这是一个阻塞调用。在 ASP.NET 应用程序中,阻止对远程资源的调用非常糟糕。在这里,您正在获取一些远程资源,这可能需要时间=>您将穿越网络边界、互联网防火墙……直到您到达远程 Web 服务器,该服务器本身为了满足请求将查询数据库……您明白了:它很慢。在这段时间里,您的 Web 应用程序一直处于等待状态,并且线程被垄断。请记住,您可以使用的工作线程数量有限,因此不要浪费它们。

解决这个非常严重的问题的方法是使用异步控制器和 I/O 完成端口。它们直接内置于 Windows 内核中,允许您执行 IO 密集型操作,而无需阻塞和独占服务器上的线程。

您的 HomeController 将变成以下样子:

public class HomeController : AsyncController
{
    public void IndexAsync()
    {
        var client = new WebClient();
        AsyncManager.OutstandingOperations.Increment();
        client.DownloadStringCompleted += (s, e) => 
        {
            AsyncManager.OutstandingOperations.Decrement();
            if (e.Error != null)
            {
                AsyncManager.Parameters["error"] = e.Error.Message;
            }
            else
            {
                var serializer = new JavaScriptSerializer();
                var model = serializer.Deserialize<FCC>(e.Result);
                AsyncManager.Parameters["licenses"] = model.Licenses.License;
            }
        };
        client.DownloadStringAsync(new Uri("http://data.fcc.gov/api/license-view/basicSearch/getLicenses?searchValue=Verizon+Wireless&format=json"));
    }

    public ActionResult IndexCompleted(License[] licenses, string error)
    {
        if (!string.IsNullOrEmpty(error))
        {
            ModelState.AddModelError("licenses", error);
        }
        return View(licenses ?? Enumerable.Empty<License>());
    }
}

There are a couple of issues with your code which I will try to address:

  1. You have a controller action which returns a JSON string and you have defined some Razor view but this razor view is never invoked from the action.
  2. You are querying a remote service which returns JSONP instead of using the JSON possibility of the API which seems more adapted.
  3. You are jeopardizing a worker thread during the fetching of the remote resource.

So let's start by our view models:

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; }
}

public class Licenses
{
    public License[] License { get; set; }
}

public class FCC
{
    public string status { get; set; }
    public Licenses Licenses { get; set; }
}

then we would have the following controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        using (var client = new WebClient())
        {
            var json = client.DownloadString("http://data.fcc.gov/api/license-view/basicSearch/getLicenses?searchValue=Verizon+Wireless&format=json");
            var serializer = new JavaScriptSerializer();
            var model = serializer.Deserialize<FCC>(json);
            return View(model.Licenses.License);
        }
    }
}

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 the format=json parameter.

And finally we could have the following ~/Views/Home/Index.cshtml view:

@model IEnumerable<License>

<table>
    <thead>
        <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>
    </thead>
    <tbody>
        @Html.DisplayForModel()
    </tbody>
</table>

and the corresponding display template which will be rendered for each element of the Licenses collection (~/Views/Home/DisplayTemplates/License.cshtml):

@model License

<tr>
    <td>
        @Html.DisplayFor(x => x.Name)
    </td>
    <td>
        @Html.DisplayFor(x => x.Frn)
    </td>
    <td>
        @Html.DisplayFor(x => x.Callsign)
    </td>
    <td>
        @Html.DisplayFor(x => x.CategoryDesc)
    </td>
    <td>
        @Html.DisplayFor(x => x.ServiceDesc)
    </td>
    <td>
        @Html.DisplayFor(x => x.StatusDesc)
    </td>
    <td>
        @Html.DisplayFor(x => x.ExpiredDate)
    </td>
    <td>
        @Html.DisplayFor(x => x.DetailUrl)
    </td>
</tr>

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:

public class HomeController : AsyncController
{
    public void IndexAsync()
    {
        var client = new WebClient();
        AsyncManager.OutstandingOperations.Increment();
        client.DownloadStringCompleted += (s, e) => 
        {
            AsyncManager.OutstandingOperations.Decrement();
            if (e.Error != null)
            {
                AsyncManager.Parameters["error"] = e.Error.Message;
            }
            else
            {
                var serializer = new JavaScriptSerializer();
                var model = serializer.Deserialize<FCC>(e.Result);
                AsyncManager.Parameters["licenses"] = model.Licenses.License;
            }
        };
        client.DownloadStringAsync(new Uri("http://data.fcc.gov/api/license-view/basicSearch/getLicenses?searchValue=Verizon+Wireless&format=json"));
    }

    public ActionResult IndexCompleted(License[] licenses, string error)
    {
        if (!string.IsNullOrEmpty(error))
        {
            ModelState.AddModelError("licenses", error);
        }
        return View(licenses ?? Enumerable.Empty<License>());
    }
}
各自安好 2024-12-12 23:13:23

这是我所做的,它在 DIV 中向我显示 Json 数据...

您的控制器...

public JsonResult GetLicenses()
        {
            var result = string.Empty;
            const string 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 != null && response.StatusCode == HttpStatusCode.OK)
                {
                    var receiveStream = response.GetResponseStream();
                    if (receiveStream != null)
                    {
                        var stream = new StreamReader(receiveStream);
                        result = stream.ReadToEnd();

                    }
                }
            }
            return Json(result,JsonRequestBehavior.AllowGet);

在 Action 中设置返回类型 Json 并输入 JsonResult

,如果您想通过 AJAX 调用它,那么这里是

$.ajax

<script type="text/javascript">
    $(document).ready(function () {
        $.ajax({
            type: 'GET',
            url: '@Url.Action("GetLicenses","Home")',
            success: function (data) {
                $('#content').html(data);
            },
            error: function (data) {
                $('#content').append(data);
            }
        });
    });

并确保您在 _Layout.cshtml 中引用 Jquery 文件。

Here is what i did and its showing me Json data in DIV...

Your Controller...

public JsonResult GetLicenses()
        {
            var result = string.Empty;
            const string 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 != null && response.StatusCode == HttpStatusCode.OK)
                {
                    var receiveStream = response.GetResponseStream();
                    if (receiveStream != null)
                    {
                        var stream = new StreamReader(receiveStream);
                        result = stream.ReadToEnd();

                    }
                }
            }
            return Json(result,JsonRequestBehavior.AllowGet);

make the return type Json and type JsonResult in Action

and if you want to call this through AJAX then here is the

$.ajax

<script type="text/javascript">
    $(document).ready(function () {
        $.ajax({
            type: 'GET',
            url: '@Url.Action("GetLicenses","Home")',
            success: function (data) {
                $('#content').html(data);
            },
            error: function (data) {
                $('#content').append(data);
            }
        });
    });

and make sure that you reference the Jquery files in _Layout.cshtml..

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文