调用FatSecret Sharp API时,此时无法启动异步操作

时间:2014-10-07 20:49:11

标签: javascript c# asp.net .net asynchronous

我试图创建一个基本的ASP.NET应用程序,使用名为FatSecret Sharp的包装器调用Fatsecret API,但是当我尝试从我的JS调用服务器端方法时出现此错误脚本,我想确定如何成功使用此包装器来创建Web应用程序。

您会注意到来自包装器的API调用明确提到它是"同步",所以我假设发生错误的是什么,我只是不知道" #39;不知道为什么,或者如何使用Web应用程序成功使用该调用。

这是我的代码:

的Javascript

var jsonData;

function search() {
    var element = document.getElementById("searchField")
    var searchTerm = element.value;

    callAJAX("FoodSearchExample", searchTerm);
}

function callAJAX(requestMethod, term) {
    var pageMethod = "default.aspx/" + requestMethod;

    $.ajax({
    url: pageMethod,
    data: JSON.stringify({ searchTerm : term }),
    type: "POST",  
    contentType: "application/json",       
    dataType: "JSON",  
    timeout: 600000,
    success: function (result) {
        ajaxCallback(result.d);
    },
    error: function (xhr, status) {
        alert(status + " - " + xhr.responseText);
    }
});

return false;
}

function ajaxCallback(serverResponse) {
    if (serverResponse !== "loadLocations") {
        //jsonData = JSON.parse(serverResponse);
        alert(serverResponse);
    }
    else
        alert("error");
}

C#

namespace HELP_Testing
{

public partial class _default : System.Web.UI.Page
{
    private static string consumerKey = "key (removed from question)";
    private static string consumerSecret = "secret (removed from question)";

    [WebMethod]
    public static string FoodSearchExample(string searchTerm)
    {
        FoodSearch foodSearch = new FoodSearch(consumerKey, consumerSecret);
        string str = "";

        var response = foodSearch.GetResponseSynchronously(new FoodSearchRequest()
        {
            SearchExpression = searchTerm
        });

        List<Food> foods = new List<Food>();

        if (response.HasResults)
        {               
            Food f;

            foreach (var food in response.foods.food)
            {
               f = new Food();
               f.FoodId = food.food_id;
               f.FoodType = food.food_type;
               f.FoodName = food.food_name;
               foods.Add(f);
            }
        }
        else
            Console.WriteLine("No results from term");

        JavaScriptSerializer serializer = new JavaScriptSerializer();
        str = serializer.Serialize(foods);

        return str;
    }

    protected void Page_Load(object sender, EventArgs e)
    {

    }
}

}

HTML

<%@ Page Language="C#" AutoEventWireup="true" Async="True"  CodeBehind="default.aspx.cs"     Inherits="HELP_Testing._default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">    
    <script type="text/javascript" src="scripts/default.js"></script>
    <script type="text/javascript" src="scripts/jquery-1.11.1.js"></script>
    <title>Healthy Eating Life Planner</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <input type="text" name="Food Search" id="searchField" />
        <button type="submit" onclick="search()">Search</button>
    </div>
    </form>
</body>
</html>

完整的错误消息是:

此时无法启动异步操作。异步操作只能使用异步处理程序或模块启动 或者在页面生命周期中的某些事件期间。如果在执行页面时发生此异常,请确保页面 被标记为Async = true。此例外还可能表示尝试调用“异步无效”空白&#39;方法,一般 ASP.NET请求处理中不受支持。相反,异步方法应该返回一个Task,调用者应该等待它#34;

2 个答案:

答案 0 :(得分:1)

是的,the problem is in GetResponseSynchronously。轮询完成是一个非常值得怀疑的方法。

有几种方法可以解决这个问题。一种是抛弃FatSearch CSharp库并使用HttpClient写入他们的JSON API。这种方法更简洁,但意味着您必须编写更多代码。

另一种方法是wrap the sort-of-EBAP APIs from FatSearch CSharp as async-compatible methods。在这种情况下,重要成员是GotResultGotErrorStartRequestAsync。请注意,您的网络方法将变为async

答案 1 :(得分:0)

而不是打电话 公共任务GetResponseSynchronously(TRequest请求)就像示例控制台App建议的那样,在像MVC这样的Web上下文中,最好添加一个异步方法,比如我下面成功写的那个:

    /// <summary>
    /// Gets the response Asynchronously.
    /// </summary>
    /// <param name="request">The request.</param>
    /// <returns>A parsed response, or throws an exception.</returns>
    public async Task<TResponse> GetResponseAsynchronously(TRequest request)
    {

        var requestUrl = CreateRequestUrl(request);

        HttpClient APIRequest = new HttpClient();

        var response = await APIRequest.GetAsync(requestUrl).ConfigureAwait(false);

        response.EnsureSuccessStatusCode();

        string downloadedString = await response.Content.ReadAsStringAsync();


        var result = ConvertClientResultString(downloadedString);                      

        return result;
    }

重要的是要注意,要获得无缝结果,您需要通过添加如下所示的响应处理方法来更改Service4u2Lib的BaseJsonService.c:

/// <summary>
    /// Handles the client result string.
    /// </summary>
    /// <param name="downloadedString">The downloaded string.</param>
    public TResultType ConvertClientResultString(string downloadedString)
    {
        // Check for html doctype and report error if found.
        int takeLength = downloadedString.Length > 20 ? 20 : downloadedString.Length;
        if (downloadedString.Substring(0, takeLength).Contains("!DOCTYPE html"))
            HandleClientError(new NotSupportedException("The service call returned html and not json"));

        var result = new TResultType();

        string json = downloadedString;

        if (result is IJSONMassager)
        {
            json = ((IJSONMassager)result).MassageJSON(downloadedString);
        }

        if (result is IJSONSelfSerialize<TResultType>)
        {
            result = ((IJSONSelfSerialize<TResultType>)result).SelfSerialize(json);
        }
        else
            result = JsonHelper.Deserialize<TResultType>(json);

        if (GotResult != null)
            GotResult(this, new EventArgs<TResultType>() { Argument = result });

        return result;
    }

基本上我们重新调整现有对象,使它们可以使用HTTPClient对象,该对象可以使用.ConfigureAwait(false)处理请求。确保回调发生的方法。