Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当存在';包含的异步函数_C#_Async Await_Singleton_Lazy Initialization - Fatal编程技术网

C# 当存在';包含的异步函数

C# 当存在';包含的异步函数,c#,async-await,singleton,lazy-initialization,C#,Async Await,Singleton,Lazy Initialization,我的网站需要初始化一些数据,只有当应用程序需要它,它必须只做一次。初始化必须调用API来获取数据 因此,基本上,我认为我需要创建一个惰性单例,它将在首次访问api时调用api。但是当我使用HttpClient类中的异步方法GetAsync时,我遇到了一个问题。调用API时发生崩溃,但我的TryCatch没有捕获异常 我试图将Piv GetPiv()转换为Task GetPiv(),但我不知道如何将其用于惰性对象 public class PivHelper { private stati

我的网站需要初始化一些数据,只有当应用程序需要它,它必须只做一次。初始化必须调用API来获取数据

因此,基本上,我认为我需要创建一个惰性单例,它将在首次访问api时调用api。但是当我使用HttpClient类中的异步方法GetAsync时,我遇到了一个问题。调用API时发生崩溃,但我的TryCatch没有捕获异常

我试图将
Piv GetPiv()
转换为
Task GetPiv()
,但我不知道如何将其用于惰性对象

public class PivHelper
{
    private static readonly Lazy<Piv> _lazyPiv = new Lazy<Piv>(GetPiv);

    public string Header()
    {
        return _lazyPiv.Value.Header;
    }

    public string Footer()
    {
        return _lazyPiv.Value.Footer;
    }

    public string Scripts()
    {
        return _lazyPiv.Value.Scripts;
    }

    public string Styles()
    {
        return _lazyPiv.Value.Styles;
    }

    private static Piv GetPiv()
    {
        try
        {
            var client = new HttpClient();

            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            HttpResponseMessage response = client.GetAsync("http://some-web-site.com").Result;

            if (response.IsSuccessStatusCode)
            {
                return response.Content.ReadAsAsync<Piv>().Result;
            }
            else
            {
                return new Piv();
            }
        }
        catch (Exception ex)
        {
            return new Piv();
        }
    }
}

public class Piv
{
    public string Header { get; set; }
    public string Footer { get; set; }
    public string Styles { get; set; }
    public string Scripts { get; set; }
}

public static class MtoHelper
{
    private static readonly Lazy<PivHelper> lazyPivHelper = new Lazy<PivHelper>(() => new PivHelper());

    public static PivHelper Piv
    {
        get
        {
            return lazyPivHelper.Value;
        }
    }
}
公共类PivHelper
{
private static readonly Lazy _lazyPiv=new Lazy(GetPiv);
公共字符串头()
{
返回_lazyPiv.Value.Header;
}
公共字符串页脚()
{
返回_lazyPiv.Value.Footer;
}
公共字符串脚本()
{
返回_lazyPiv.Value.Scripts;
}
公共字符串样式()
{
返回_lazyPiv.Value.style;
}
私有静态Piv GetPiv()
{
尝试
{
var client=新的HttpClient();
client.DefaultRequestHeaders.Accept.Add(新的MediaTypeWithQualityHeaderValue(“应用程序/json”);
HttpResponseMessage response=client.GetAsync(“http://some-web-site.com三、结果;
if(响应。IsSuccessStatusCode)
{
返回response.Content.ReadAsAsync().Result;
}
其他的
{
返回新的Piv();
}
}
捕获(例外情况除外)
{
返回新的Piv();
}
}
}
公共类Piv
{
公共字符串头{get;set;}
公共字符串页脚{get;set;}
公共字符串样式{get;set;}
公共字符串脚本{get;set;}
}
公共静态类MtoHelper
{
private static readonly lazyPivHelper=new Lazy(()=>new PivHelper());
公共静态PivHelper Piv
{
得到
{
返回lazyPivHelper.Value;
}
}
}
My_Layout.cshtml文件

<!DOCTYPE html>
<html>
<head>
    <!-- Instead of using our own copy of the piv.css, we use the one
         coming from the webservices -->
    <!--<link href="~/content/piv.css" rel="stylesheet" type="text/css">-->
    @MtoHelper.Piv.Styles()

    <link rel="shortcut icon" href="/favicon.ico" />
</head>

<body>
    <header id="pageHeaderContainer" class="container">
        @MtoHelper.Piv.Header()
    </header>

    <section id="main" class="container">
        @RenderBody()
    </section>

    <footer id="pageFooterContainer" class="container">
        @MtoHelper.Piv.Footer()
    </footer>

    @MtoHelper.Piv.Scripts()
</body>
</html>

@MtoHelper.Piv.Styles()
@MtoHelper.Piv.Header()
@RenderBody()
@MtoHelper.Piv.Footer()
@MtoHelper.Piv.Scripts()

您需要使用
async
wait
关键字。使用
.Result
会导致问题。您可以实现如下所示的
AsyncLazy
类,这将允许您确保对
GetPiv
的调用只发生一次

public class AsyncLazy<T> : Lazy<Task<T>>
{
    public AsyncLazy(Func<T> valueFactory) : base(() => Task.Run(valueFactory))
    {
    }

    public AsyncLazy(Func<Task<T>> taskFactory) : base(() => Task.Run(taskFactory))
    {
    }
}
公共类异步延迟:延迟
{
public(Func valueFactory):基(()=>Task.Run(valueFactory))
{
}
公共异步(Func taskFactory):基(()=>Task.Run(taskFactory))
{
}
}
然后,您必须修改代码以利用上述关键字:

public class PivHelper
{
    static readonly AsyncLazy<Piv> _lazyPiv = new AsyncLazy<Piv>(() => GetPivAsync());

    public Task<Piv> PivTask => _lazyPiv.Value;

    static Task<Piv> GetPivAsync()
    {
        try
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                var response = await client.GetAsync("http://some-web-site.com");

                if (response.IsSuccessStatusCode)
                {
                    return await response.Content.ReadAsAsync<Piv>();
                }
                else
                {
                    return new Piv();
                }
            }
        }
        catch (Exception ex)
        {
            return new Piv();
        }
    }
}

public class Piv
{
    public string Header { get; set; }
    public string Footer { get; set; }
    public string Styles { get; set; }
    public string Scripts { get; set; }
}
公共类PivHelper
{
静态只读AsyncLazy _lazyPiv=new AsyncLazy(()=>GetPivAsync());
公共任务PivTask=>\u lazyPiv.Value;
静态任务GetPivAsync()
{
尝试
{
使用(var client=new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(新的MediaTypeWithQualityHeaderValue(“应用程序/json”);
var response=wait client.GetAsync(“http://some-web-site.com");
if(响应。IsSuccessStatusCode)
{
return wait response.Content.ReadAsAsync();
}
其他的
{
返回新的Piv();
}
}
}
捕获(例外情况除外)
{
返回新的Piv();
}
}
}
公共类Piv
{
公共字符串头{get;set;}
公共字符串页脚{get;set;}
公共字符串样式{get;set;}
公共字符串脚本{get;set;}
}
然后,在API代码中,您可以这样使用帮助程序(我假设使用ASP.NET Core作为其Web API):

公共类PIV控制器:控制器
{
私人只读PivHelper\u助手;
公共PIV控制器(PivHelper PivHelper)
{
_helper=pivHelper;
}
公共异步任务GetPiv()
{
var piv=等待_helper.PivTask;
//按piv操作,或直接返回它。。。
}
}
更新

根据OPs编辑,我需要更新我的答案

你没有正确地进行MVC。整个想法是分离关注点,并根据以下原则(如SOLID)推广最佳实践。您的视图不应了解
PivHelper
,而应了解
Piv
模型,您的控制器应了解
PivHelper
,因为它是
Piv
的提供者


至于需要一个模型作为布局的一部分,这是一场不同的战斗。我建议您不要这样做,并建议您将布局仅限于
.css
的链接和
.js
的脚本标记,并且使用最少的元素。

调用
.Result
通常是个坏主意。你能让
GetPiv()异步吗<代码>公共静态异步任务GetPiv()
?然后,您可以等待其中调用的异步操作。这是我试图做的,但是,如果GetPiv是一个任务,那么如何使用惰性对象呢。这就是我被困的地方。问得好。这看起来很有用:我正在MVC5项目中使用_layour.cshtml文件中的结果。事实上,我在描述中的例子是真实事物的一个较小版本。
public string Header()
实际上是一个
public MvcHtmlString Header()
,因此我可以在视图中直接使用它。因此,它不能是任务确实可以,向我显示与视图相对应的控制器操作,我将更新我的an
public class PivController : Controller
{
    private readonly PivHelper _helper;

    public PivController (PivHelper pivHelper)
    {
        _helper = pivHelper;
    }

    public async Task<IActionResult> GetPiv()
    {
        var piv = await _helper.PivTask;
        // Act on the piv, or simply return it...
    }
}