8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

使用 WebApplicationFactory 进行基准测试

Nidhin Paul 2月前

97 0

我在登录时遇到问题,不知道该怎么办。我很确定这与我的程序有关。cs:使用 MudBlazor.Services;使用 Microsoft.AspNetCore.Authentication.OpenIdConnect;使用

我在登录时遇到问题,不知道该怎么办。我很确定这与我的 program.cs 有关:

using MudBlazor.Services;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Serilog;
using System.Configuration;


internal class Program
{
    private static void Main(string[] args)
    {
        WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

        Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .CreateBootstrapLogger();
        Log.Information("App started");

        builder.Host.UseSerilog((ctx, lc) => lc
            .MinimumLevel.Information()
            .WriteTo.Console());

        builder.Logging.AddConsole();

        //adding dbContext

        string[]? initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ') ?? builder.Configuration["MicrosoftGraph:Scopes"]?.Split(' ');
        builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
                .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
                    .AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
                    .AddInMemoryTokenCaches();

        builder.Services.AddControllersWithViews()
            .AddMicrosoftIdentityUI();

        builder.Services.AddAuthorization(options =>
        {
            options.FallbackPolicy = options.DefaultPolicy;
        });

        builder.Services.AddRazorPages();
        builder.Services.AddServerSideBlazor()
            .AddMicrosoftIdentityConsentHandler();

        builder.Services.AddRazorComponents()
            .AddInteractiveServerComponents();

        builder.Services.AddMudServices(config =>
        {
            config.SnackbarConfiguration.PositionClass = MudBlazor.Defaults.Classes.Position.TopCenter;
            config.SnackbarConfiguration.PreventDuplicates = true;
            config.SnackbarConfiguration.NewestOnTop = false;
            config.SnackbarConfiguration.ShowCloseIcon = true;
            config.SnackbarConfiguration.RequireInteraction = true;
            config.SnackbarConfiguration.HideTransitionDuration = 300;
            config.SnackbarConfiguration.ShowTransitionDuration = 300;
            config.SnackbarConfiguration.SnackbarVariant = MudBlazor.Variant.Filled;
        });

        builder.Services.AddMudBlazorDialog();

        //Adding my services


        var app = builder.Build();

        if (!app.Environment.IsDevelopment())
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();

        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();
        app.UseAntiforgery();

        app.MapControllers();
        app.MapRazorComponents<App>()
            .AddInteractiveServerRenderMode();
        app.Run();
    }
}

每次我启动我的应用程序时,第一次都会出现此错误:[MsIdWeb] 获取令牌期间发生错误:没有向 AcquireTokenSilent 调用传递任何帐户或登录提示。

但是登录立即生效,因为它会重试。我只是不知道该怎么做,我认为我无法向登录用户添加声明,因为该用户最初为空。

一开始,我忽略了错误,因为登录仍然可以立即进行,并且我没有遇到任何问题,但是前几天我尝试添加声明时,页面立即卡住了,并且根据日志,每次用户为空时,应用程序都会尝试新的登录。

我尝试了多种不同的方法,而不是 AddAuthentication,但没有成功。

我尝试的另一件事是手动重新登录,当 MsalUiRequiredException 弹出时,它只会强制我登录。但我再次将其删除,因为每次打开网站都会发生这种情况。

帖子版权声明 1、本帖标题:使用 WebApplicationFactory 进行基准测试
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Nidhin Paul在本站《asp.net-core》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 当 auzre 配置没有下游 api 范围时,我收到此错误消息。您可以检查 appsettings.json 中是否包含以下内容。

      "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "Domain": "xxx.onmicrosoft.com",
        "TenantId": "xxxx",
        "ClientId": "xxxx",
        "ClientSecret": "xxxx",
        "CallbackPath": "/signin-oidc",
        "Scopes": "api://85a8853a-64c7-4023-ae90-7f709bfc3bb4/access_as_user"
      },
    

    确保“前端 Web 应用程序”包含“后端公开 API”的范围

    调用后端api时:

                string[] scopes = new string[] { "api://85a8853a-64c7-4023-ae90-7f709bfc3bb4/access_as_user" };
                string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
    
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                var response = await _httpClient.GetAsync("https://localhost:7299/weatherforecast");
    
  • 你好@Qiang Fu,我创建了 api,但是我应该把后端 api 的代码放在哪里?我不知道在哪里调用它。

  • @kas 它实际上是 azure ad 的“代表”流程。(前端 mvc 和后端 api 均受 aad 保护,然后 mvc 可以使用访问令牌调用后端。)我可以稍后写一个小样本的详细步骤。

  • 不过我想我遇到了另一个问题。我尝试在 FakeAuthenticationStateProvider 中使用你的方法,但当我尝试获取令牌时,出现了 user is null 异常。

  • @kas 您使用的是哪种全局渲染模式?您是否使用 InteractiveServer 并禁用预渲染?

  • 我们正在考虑使用 BenchmarkDotNet 之类的工具对 .NET 6 项目中的一些 REST API 端点进行一些基准测试工作。我们很欣赏 BenchmarkDotNet 之类的工具......

    我们正在考虑使用 BenchmarkDotNet 之类的工具对 .NET 6 项目中的一些 REST API 端点进行一些基准测试工作。

    我们赞赏 BenchmarkDotNet 这样的工具最适合对单个类进行基准测试。但有时我们需要调查 API 端点的内存使用情况,而我们最初并不知道内存效率低下的原因。

    对于这些情况,我们理想情况下应该有一个设置,使我们能够在迭代想法和监控整体内存使用情况时在本地调用 API。

    一种方法是使用 WebApplicationFactory 调用端点,就像我们在集成测试中所做的那样。但我们的问题是,这是否有效,或者我们是否应该测量调用 API 的内存使用量,而不是 API 本身所消耗的内存量?

  • 我们有一个运行 RabbitMQ 3.8.5 和 RabbitMQ.Client 5.2.0 的系统。系统使用 Rabbit 的方式之一是创建一个消费者来等待来自不同执行器的特定命令...

    我们有一个运行 RabbitMQ 3.8.5 和 RabbitMQ.Client 5.2.0 的系统。系统使用 Rabbit 的方式之一是,当客户端发出长轮询 Web 请求时,创建一个消费者来等待来自不同可执行文件的特定命令。Web 请求通过 .Net 6.0 Web API 传入,每个客户端都会创建消费者,因为所述命令发布在特定于该客户端的队列上。在给定的超时之后,消费者将被处置,客户端将重新启动长轮询请求。我们能够支持 1500 多个客户端/消费者同时发出长轮询请求。在我们升级到 RabbitMQ 3.13.3 和 RabbitMQ.Client 6.8.1 之前,这一直运行良好。现在,当大约 700 个客户端发起此长轮询请求时,会发生超时异常。当 500 个客户端长时间连接(> 1 小时)时,也会发生同样的情况。我们也尝试使用 EasyNetQ,因为我们在系统的其他部分使用该库,但遇到了相同的错误和行为,即超时,随后 RabbitMQ 服务器终止连接。

    进一步的调查似乎表明,发生超时异常时会错过心跳,并且 RabbitMQ 服务器会终止连接,从而导致我们这边出现多米诺骨牌效应。我们尚未找出导致超时的原因,并阻止了与 RabbitMQ 相关的所有操作。

    编辑 这里有一些可能有帮助的细节,版本升级之间任何设置都没有改变。

    • 目标工作量为 1500+ 个客户,并保持现状
    • VM、Windows Server 2022 Standard x64、32 GB RAM、2.3 Ghz CPU
    • 队列仍然是经典的,并且保持原样。

    下面提供了一些详细信息:

    这是错误首次发生时出现的初始异常:

        at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout)
        at RabbitMQ.Client.Impl.ModelBase.QueueDeclare(String queue, Boolean passive, Boolean 
         durable, Boolean exclusive, Boolean autoDelete, IDictionary`2 arguments)
        at RabbitMQ.Client.Impl.ModelBase.ConsumerCount(String queue)
    

    EasyNetQ 错误

    System.TimeoutException: The operation has timed out.
       at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout)
       at RabbitMQ.Client.Impl.ModelBase.QueueDeclare(String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, IDictionary`2 arguments)
       at RabbitMQ.Client.Impl.AutorecoveringModel.QueueDeclare(String queue, Boolean durable, Boolean exclusive, Boolean autoDelete, IDictionary`2 arguments)
       at EasyNetQ.RabbitAdvancedBus.<>c__DisplayClass51_0.<QueueDeclareAsync>b__0(IModel x)
       at EasyNetQ.Persistent.PersistentChannel.InvokeChannelActionAsync[TResult,TChannelAction](TChannelAction channelAction, CancellationToken cancellationToken)
       at EasyNetQ.RabbitAdvancedBus.QueueDeclareAsync(String name, Action`1 configure, CancellationToken cancellationToken)
       at EasyNetQ.AdvancedBusExtensions.QueueDeclare(IAdvancedBus bus, String name, Boolean durable, Boolean exclusive, Boolean autoDelete, CancellationToken cancellationToken)
    

    初始消费者守则

     ncChannel.QueueDeclare(queueName, true, false, false, null);
     ncChannel.ExchangeDeclare(ExchangeName, ExchangeType.Topic, true, false, null);
     ncChannel.QueueBind(queueName, ExchangeName, routingKey);
    Channel<BasicDeliverEventArgs> responseChannel = Channel.CreateBounded<BasicDeliverEventArgs>(channelOptions);
    EventHandler<BasicDeliverEventArgs> nextCommandHandler = async (object sender, BasicDeliverEventArgs msg) =>
    {
        try
        {
            if (msg != null && msg.Body.ToArray() != null)
            {
                string msgBody = Encoding.UTF8.GetString(msg.Body.ToArray());
                //log
            }
            else
            {
                //log
            }
            await responseChannel.Writer.WriteAsync(msg);
            responseChannel.Writer.TryComplete();
        }
        catch (Exception ex)
        {
            //log
        }
    };
    consumer.Received += nextCommandHandler;
     bool autoAck = true;
     consumerTag = ncChannel.BasicConsume(queueName, autoAck, consumer);
    

    尝试将消费者更改为异步事件基本消费者

    Channel<string> responseChannel = Channel.CreateBounded<string>(channelOptions);
    
    ncChannel.QueueDeclare(queueName, true, false, false, null);
    ncChannel.ExchangeDeclare(ExchangeName, ExchangeType.Topic, true, false, null);
    ncChannel.QueueBind(queueName, ExchangeName, routingKey);
    AsyncEventingBasicConsumer consumer = new AsyncEventingBasicConsumer(ncChannel);
    AsyncEventHandler<BasicDeliverEventArgs> nextCommandHandler = async (object sender, BasicDeliverEventArgs msg) =>
    {
        try
        {
            if (msg != null && msg.Body.ToArray() != null)
            {
                string msgBody = Encoding.UTF8.GetString(msg.Body.ToArray());
                //log
            }
            else
            {
                //log
            }
            await responseChannel.Writer.WriteAsync(msg);
            responseChannel.Writer.TryComplete();
            await Task.Yield();
        }
        catch (Exception ex)
        {
            //log
        }
    };
    consumer.Received += nextCommandHandler;
    
    bool autoAck = true;
    consumerTag = ncChannel.BasicConsume(queueName, autoAck, consumer);
    

    EasyNetQ 消费者代码

    var queue = _rabbitBus.Advanced.QueueDeclare(queueName, true, false, false);
    consumer = _rabbitBus.Advanced.Consume(queue, (body, properties, info) => Task.Factory.StartNew(async () =>
    {
        try
        {
            string msgBody = null;
            if (body.ToArray() != null)
            {
                msgBody = Encoding.UTF8.GetString(body.ToArray());
                //log
            }
            else
            {
                //log
            }
            await responseChannel.Writer.WriteAsync(msgBody);
            responseChannel.Writer.TryComplete();
            await Task.Yield();
        }
        catch (Exception ex)
        {
            //log
        }
    }));
    
  • 这是我制作的一个可以重现该问题的 repo,自述文件显示了如何运行测试来重现该问题

  • SIDU 2月前 0 只看Ta
    引用 10

    当我使用 MyConfig 目标构建我的项目时,我希望代码得到优化,并且我不想要任何 .pdb 文件。为了实现这一点,我在 ro 中创建了一个像这样的 Directory.Build.props 文件......

    当我使用目标构建我的项目时 MyConfig ,我希望代码得到优化,并且我不想要任何 .pdb 文件。

    在项目的根目录中 Directory.Build.props 创建了一个

    <Project>
      <PropertyGroup>
        <Configurations>Debug;Release;MyConfig</Configurations>
      </PropertyGroup>
    
      <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'MyConfig|AnyCPU'">
        <DebugType>none</DebugType>
        <Optimize>true</Optimize>
        <DefineConstants>TRACE</DefineConstants>
      </PropertyGroup>
    
    </Project>
    

    现在,如果我运行此命令,我将获得预期的输出:

    dotnet build .\BuildPoc.sln -c MyConfig
    

    但是,直接构建项目时:

    dotnet build .\src\MyProject\MyProject.csproj -c MyConfig
    

    然后 .pdb 文件就创建好了。

    我不明白为什么会有差异?

    难道 dotnet build 不应该尊重 Directory.Build.props 不管吗?

    我在这里创建了一个示例存储库,其中有一个简单的项目显示了这种行为: https://github.com/mortenbock/BuildPoc

    编辑:

    此外,我刚刚发现,如果我运行这两个命令:

    dotnet build .\BuildPoc.sln -c MyConfig
    dotnet publish .\src\MyProject\MyProject.csproj -c MyConfig --no-build
    

    然后我收到这个错误,似乎假设 dotnet publish 应该有一个 .pdb 文件?

    C:\Program Files\dotnet\sdk\8.0.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(351,5): error MSB3030:
     Could not copy the file "obj\MyConfig\net8.0\MyProject.pdb" because it was not found. [D:\Projects\BuildPoc\sr
    c\MyProject\MyProject.csproj]
    
  • 引用 11

    与 rabbitmq 维护人员讨论后,似乎现在需要设置 ThreadPool.MinThreads() 应用程序的以避免 rabbitmq 客户端操作的线程耗尽。他们甚至不知道为什么这是 6.x 版客户端库的要求,建议 WIP 版本 7.x 可以解决此问题。

    您可以在此处查看讨论 https://github.com/rabbitmq/rabbitmq-dotnet-client/discussions/1635

  • 通过传递显式平台参数,可以解决构建和发布问题 -p:Platform=AnyCPU .

    • 构建项目:
    dotnet build .\src\MyProject\MyProject.csproj -c MyConfig -p:Platform=AnyCPU
    
    • 发布项目:
    dotnet publish .\src\MyProject\MyProject.csproj -c MyConfig --no-build -p:Platform=AnyCPU
    

    或者, $(Platform) 从条件中删除检查,因为所有命令行都有 -c MyConfig .

     <PropertyGroup Condition="'$(Configuration)' == 'MyConfig'">
    

    目前,我还没有找到官方的解释。


    另一种方法是使用 Directory.Build.targets 文件, 稍后再导入 .
    从您的评论来看,导入和评估的顺序很重要。

    您可以将此 Directory.Build.props 文件重命名为 Directory.Build.targets .
    当这样做时,您构建项目的初始尝试将会成功。

    dotnet build .\src\MyProject\MyProject.csproj -c MyConfig
    

    要发布项目,您必须一次性构建和发布它,因此删除 --no-build 或使用上一个/上面的发布建议 )。

    dotnet publish .\src\MyProject\MyProject.csproj -c MyConfig
    
  • 引用 13

    我选择了改变条件的替代方案。不过这很奇怪。我尝试在构建期间输出 $(Platform),两种情况下都是 AnyCPU,但也许这与构建中的哪个点设置该值有关?可能是有时直到评估条件后才设置。

  • 我遵循了您提到的类似步骤,甚至详细的--verbosity 也没有让我变得更加明智。

  • Directory.Build.props 很早就被导入了,并且是在“通用”项目支持之前。除非有明确需要,否则请避免使用 Directory.Build.props,而应优先使用 Directory.Build.targets。(名称是任意的。这两个文件都是“完整”的 MSBuild 文件,没有任何限制,即属性不需要位于 .props 中。)

  • 标题“仅在构建 .sln 文件时才尊重 Directory.Build.props”中的假设是不正确的,并且不是正在发生的事情。

    A Directory.Build.props 很早就被导入了,在“通用”项目支持之前。 $(Configuration) $(Platform) 属性在“通用”项目支持中定义在 Directory.Build.props .

    在命令行上 Configuration 定义 Platform 和/或 Directory.Build.props 导入之前,命令行上的属性将被定义为全局属性。

    对于解决方案文件,MSBuild 首先将解决方案“翻译”为“元项目”。元项目通过传递解决方案中的和 Configuration Platform

    默认 Configuration 值为 Debug .

    BuildPoc.sln 解决方案中的所有项目都以 \'Any CPU\' 作为 Platform 。由于只有一个 Platform 正在使用,因此它将是默认值。

    (sln 元项目会将解决方案中的“Any CPU”映射到项目的“AnyCPU”。)

    为什么 dotnet build .\BuildPoc.sln -c MyConfig 有效?因为 sln 为项目提供了 Configuration 价值 Platform

    为什么不起作用 dotnet build .\src\MyProject\MyProject.csproj -c MyConfig ?因为在项目中, Configuration 后定义了 Platform Directory.Build.props 。使用 -c 时, $(Configuration)|$(Platform) 的值 MyConfig| PropertyGroup Condition ,并且 DebugType , Optimize DefineConstants 属性不会改变。(这也是在 publish 针对项目运行时出现 MSB3030 错误的原因。)

    您可以通过添加以下内容来确认 Directory.Build.props

      <PropertyGroup>
        <TraceConfiguration Condition="'$(Configuration)' == ''">Configuration has no value.</TraceConfiguration>
        <TraceConfiguration Condition="'$(Configuration)' != ''">Configuration has the value '$(Configuration)'.</TraceConfiguration>
        <TracePlatform Condition="'$(Platform)' == ''">Platform has no value.</TracePlatform>
        <TracePlatform Condition="'$(Platform)' != ''">Platform has the value '$(Platform)'.</TracePlatform>
      </PropertyGroup>
    
      <Target Name="ShowPropsTrace" BeforeTargets="BeforeBuild">
        <Message Text="*** $(TraceConfiguration)"/>
        <Message Text="*** $(TracePlatform)"/>
      </Target>
    

    根据经验法则,避免使用, Directory.Build.props 而优先使用 Directory.Build.targets 。真正需要很早就导入的情况很少见。 Directory.Build.props .

    Directory.Build.props 名称 Directory.Build.targets 是任意的。这两个文件都是“完整”的 MSBuild 文件,没有任何限制,也就是说,属性不需要包含在 .props 中。

    参见“ MSBuild 如何构建项目 ”并注意评估和执行阶段。

    解决方案和项目的简单修复是将 Directory.Build.props 文件重命名为 Directory.Build.targets .

    由于 Configuration 编译器属性仅与 Configuration .

返回
作者最近主题: