Json响应不会在视图中输出,但会提示我下载该文件

时间:2011-09-21 18:40:18

标签: c# json asp.net-mvc-3 c#-4.0 jsonp

我正在使用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结果的Controller动作 我现在将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);


        }

3 个答案:

答案 0 :(得分:1)

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

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

我建议您更改ActionMethod以执行以下操作,并创建名为“许可证”的视图

此外,您的示例响应有点棘手。它比原始许可证对象的数组更复杂,并且包含?()。 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文件中的属性名称,因为新的License对象不再具有相同的属性名称。

AJAX可能是另一个问题,但如果我遇到一个很好的例子,我会在这里回复

答案 1 :(得分:1)

我会尝试解决您的代码中的一些问题:

  1. 你有一个控制器动作,它返回一个JSON字符串,你已经定义了一些Razor视图,但是从不会从动作中调用这个剃刀视图。
  2. 您正在查询返回JSONP的远程服务,而不是使用似乎更适应的API的JSON可能性。
  3. 在获取远程资源期间,您正在危害工作线程。
  4. 让我们从我们的视图模型开始:

    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应用程序中非常糟糕。在这里你获取一些可能需要时间的远程资源=&gt;你将遍历网络边界,互联网防火墙,......直到你点击远程网络服务器本身,为了服务请求将查询数据库,...你明白了:它很慢。在这段时间里,您的Web应用程序正在等待并且线程被垄断。请记住,您可以使用有限数量的工作线程,因此不要浪费它们。

    解决此问题very serious issue的方法是使用asynchronous controllers和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>());
        }
    }
    

答案 2 :(得分:0)

这是我做的,它在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);

返回类型Json并在Action

中键入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文件..