等待操作员与lambda一起使用时给出问题

时间:2018-06-23 12:02:54

标签: c# multithreading task

我有2个实体,我想将一些数据从第二个实体复制到第一个实体,然后我想返回一个简单的字符串,表示成功。我正在使用Polly发出http请求。我打算在json中获取数据然后将其转换为我的Entity模型并执行我可以做的操作,但是同时调用返回不同类型(可能是稍有不同的数据模型)的两个任务时都给出了错误。我在多线程方法中不是很好。 >

public interface IMyRepository 
{
    string ValidateData(MyData myData);
}


public class MyRepository :IMyRepository 
{        private  readonly RetryPolicy<HttpResponseMessage> _httpRequestPolicy;

    public MyRepository()
    {

        _httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(
             r => r.StatusCode == HttpStatusCode.InternalServerError)
         .WaitAndRetryAsync(3,
             retryAttempt => TimeSpan.FromSeconds(retryAttempt), (exception, timeSpan, retryCount, context1) =>
             {
                 var msg = $"Retry {retryCount} implemented with Pollys RetryPolicy " +
                 $"of {context1.PolicyKey} " +
                 $"at {context1.ExecutionKey}, " +
                 $"due to: {exception}.";


             });
    }

    public  string  ValidateData(MyData MyData)
    {            
       var MyDataOne= Task<MyData>.Factory.StartNew(() => await  MyRepository.getProfileOne());
       var MyDataTwo= Task<MyData>.Factory.StartNew(() => await  MyRepository.getProfileTwo());
       //Update some property of MyDataOne on basis of MyDataTwo and return true or fasle in variable **result**
        return result;
    }

    public static async Task<InsuranceCompanyData> getCusomerProfile()
    {
        var httpClient = GetHttpClient();
        string requestEndpoint = "numbers/Get";

        HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint));

        IEnumerable<int> numbers = await httpResponse.Content.ReadAsAsync<IEnumerable<int>>();
        return  new InsuranceCompanyData();
    }
    private  static HttpClient GetHttpClient()
    {
        var httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri(@"http://localhost:2351/api/");
        httpClient.DefaultRequestHeaders.Accept.Clear();
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        return httpClient;
    }
}

public static async  Task<MyData> getProfileOne()
{
    var httpClient = GetHttpClient();
    string requestEndpoint = "/numbers/Get1";

    HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint));

   // IEnumerable<string> data1= await httpResponse.Content.ReadAsAsync<IEnumerable<string>>();
    return  new MyData();
}

public static async  Task<MyData> getProfileTwo()
{
    var httpClient = GetHttpClient();
    string requestEndpoint = "/numbers/Get2";

    HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint));

  //  IEnumerable<string> data2= await httpResponse.Content.ReadAsAsync<IEnumerable<string>>();
    return  new MyyData();
}

private  static HttpClient GetHttpClient()
{
    var httpClient = new HttpClient();
    httpClient.BaseAddress = new Uri(@"http://localhost:2351/api/");
    httpClient.DefaultRequestHeaders.Accept.Clear();
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    return httpClient;
}

我得到这些错误:

  

“ await”运算符只能在异步lambda表达式中使用。考虑使用'async'修饰符标记此lambda表达式。

  

非静态字段,方法或属性'MyRepository._httpRequestPolicy'要求对象引用

2 个答案:

答案 0 :(得分:1)

请使用Task.Factory.StartNew

,而不要使用不推荐使用的Task.Run,它不支持异步lambda(在这里甚至不需要)。
var profileOneTask = Task.Run(() => getProfileOne());
var profileTwoTask = Task.Run(() => getProfileTwo());

请注意,我更改了变量名称以反映它们的实际含义。它们是在某些时候可能会产生结果的任务。它们不是这些操作的结果。

对于第二个问题,应将_httpRequestPolicy声明为实例成员,而应将其声明为静态成员,以使其在没有实例的情况下可用。但是,如注释中所述,您可以只创建getProfileOnegetProfileTwo实例方法。

答案 1 :(得分:0)

为什么不更改ValidateData签名并将async关键字添加到方法中?

    public async Task<string> ValidateDataAsync(MyData MyData)
    {            
       var task1 = Task<MyData>.Factory.StartNew(() => MyRepository.getProfileOne());
       var task2 = Task<MyData>.Factory.StartNew(() => MyRepository.getProfileTwo());

       await Task.WhenAll(task1, task2)       

       //Update some property of MyDataOne on basis of MyDataTwo and return true or fasle in variable **result**
        return result;
    }

正如@Camilo Terevinto所说,最好使用Task.Run而不是TaskFactory.StartNew

Task.Run vs Task.Factory.StartNew