عمل نکردن event ها

سوال شده توسط: علی شاکری

تاریخ ثبت: ۱۴۰۲/۰۱/۰۳

بازدید: 552

پاسخ: 24

تگ: Asp.net Core


سلام استاد

نمیدونم چرا event ها پابلیش نمیشن

میخام یک notification برای کاربر اضافه کنم و یک sms هم بدم  نمیشه 

دیباگم کردم ولی انگار event handler اجرا نمیشه

پاسخ ها

محمد اشرافی

سلام وقت بخیر ، Event رو پابلیش کردین ؟ توی این عکس ها که این اتفاق نیوفتاده ( قبلا توی متد SaveChangeAsync این کار رو انجام داده بودیم )

علی شاکری

بله استاد داخل همون متد save هست

با همون custom publish که خودتون درست کردید

علی شاکری

الان گیر میده به save کردن نوتیفیکیشن یوزر

میگه هنوز عملیات قبلی تموم نشده

محمد اشرافی

خطایی که میده رو بزارید ببینم چیه

علی شاکری

سلام استاد

هیچ اروری نمیده

طبق این عکس بعد از بریک پوینت اول به هیچ کدوم دیگه نمیرسه و پیام موفقیت میده

علی شاکری

استاد این ارور را با serilog گرفتم

An exception occurred while iterating over the results of a query for context type '"EShop.Infrastructure.Persistent.Ef.ShopDbContext"'."

""System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.

  at Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()

  at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()"

علی شاکری

System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.

  at Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()

  at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()

  at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)

  at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)

  at EShop.Infrastructure._Utilities.BaseRepository`1.GetTracking(Int64 id) in E:\Projects\EShop\EShop.Infrastructure\_Utilities\BaseRepository.cs:line 23

  at EShop.Application.Orders._EventHandlers.SendSmsOrderSendedEventHandler.Handle(OrderSended notification, CancellationToken cancellationToken) in E:\Projects\EShop\EShop.Application\Orders\_EventHandlers\SendSmsOrderSendedEventHandler.cs:line 27

محمد اشرافی

سلام مجدد ، مشکل از GetTracking اتونه ، به صورت معمولی دریافت اش کنید ببینم مشکل حل میشه 

و مورد بعدی اینکه Notification هارو بهتره  توی  یه Aggregate  با User قرار ندین چون تعداد Notification ها میره بالا و برای هر بار گرفتن User باید کل Notification هارو هم از دیتابیس دریافت کنید

علی شاکری

سلام استاد

مشکل حل نشد

من اومدم کلا یه aggregate برای نوتیفیکیشن درست کردم و دوباره مثل عکس زیر تغییر دادم ولی مشکل داره

فک کنم اصلا نمیشه در eventhandler با روش mediatR کلا کوئری بزنیم و اطلاعات واکشی کنیم و یا save کنیم

چون عملیات save قبلی تموم نشده و ما اومدیم پابلیش رو در متد save قرار دادیم

علی شاکری

اینم خطاش

{"@t":"2023-03-29T02:50:07.3537813Z","@mt":"An exception occurred while iterating over the results of a query for context type '{contextType}'.{newline}{error}","@l":"Error","@x":"System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.\r\n   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()","contextType":"EShop.Infrastructure.Persistent.Ef.ShopDbContext","newline":"\r\n","error":"System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.\r\n   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()","EventId":{"Id":10100,"Name":"Microsoft.EntityFrameworkCore.Query.QueryIterationFailed"},"SourceContext":"Microsoft.EntityFrameworkCore.Query","ActionId":"e7a0ee82-c8ba-4712-b756-f235b47c8043","ActionName":"/Admin/Orders/Show","RequestId":"0HMPG006EDKEE:00000115","RequestPath":"/Admin/Orders/Show/3","ConnectionId":"0HMPG006EDKEE"}

محمد اشرافی

طبیعتا نباید مشکی پیش بیاد چون هر چند بار بخوایم میتونیم SaveChange  رو فراخوانی کنیم ولی این وسط مشکلی که پیش میاد اینه که میوفته توی یه حلقه و هی Event رو پابلیش میکنه  ( چون توی EventHandler هم دوباره صداش می زنیم ، کاری که باید انجام بدین اینه که بعد از اینکه Event هارو پابلیش کردین ، لیست Event هارو پاک کنید ) 

توی Aggregate root یه متد به اسم ClearEvents بسازید و صداش بزنید 

محمد اشرافی

یعنی به این شکل بشه :

 private async Task PublishEvents(List<AggregateRoot> modifiedEntities)
    {
        foreach (var entity in modifiedEntities)
        {
            var events = entity.DomainEvents.ToList();
            entity.ClearnEvents();
            foreach (var domainEvent in events)
            {
                await _publisher.Publish(domainEvent,PublishStrategy.ParallelNoWait);
            }
        }
    }

علی شاکری

سلام استاد

من اومدم این entity.DomainEvents.Clear(); رو بجای clearevents اضافه کردم ولی بازم کار نمیکنه

علی شاکری

private async Task PublishEvents(List<AggregateRoot> modifiedEntities)
    {
        foreach (var entity in modifiedEntities)
        {
            var events = entity.DomainEvents.ToList();
            entity.DomainEvents.Clear();
            foreach (var domainEvent in events)
            {
                await _publisher.Publish(domainEvent, PublishStrategy.ParallelNoWait);
            }
        }
    }

علی شاکری

[22:25:47 ERR] An exception occurred while iterating over the results of a query for context type 'EShop.Infrastructure.Persistent.Ef.ShopDbContext'.
System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.ConcurrencyDetector.EnterCriticalSection()
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()

محمد اشرافی

SaveChange توی Event Handler رو بردارین مشکل حل میشه ؟

علی شاکری

سلام استاد

بازم این ارور رو میده

InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.

علی شاکری

استاد من اومدم در infrastructurebootstrapper کد رو به این تغییر دادم

services.AddDbContext<ShopDbContext>(option =>
            {
                option.UseSqlServer(connectionString);
            }, ServiceLifetime.Transient);

سرویس لایف تایم رو به transient تغییر دادم و در eventhandler هم save را پاک نکردم و الان درست شد و کار میکنه

 

به نظرتون این تغییر در servicelifetime مشکل ساز نمیشه؟

 

محمد اشرافی

فکر نمیکنم مشکل خاصی پیش ، به صورت پیشفرض خود اش Scope ه ، ولی اگر Singleton اش میکردین به مشکل میخورد

علی شاکری

خب استاد الان من باید تو همه پروژه های بزرگ این تغییر رو انجام بدم؟

الان من از rich مدل استفاده کردم.به نظرم روش خوبیه فقط یکم توی کوئری گرفتن با dapper سختم بود.مثلا برای نوشتن کوئری صفحه بندی productshop هنوز کامل متوجه نشدم و از chatgpt کمک گرفتم خخخ

الان برای نوشتن کوئری های پیچیده ابزار خاصی هست یا باید بشینیم و بنویسیم؟

محمد اشرافی

نه نیازی نیست من همیشه همینطور استفاده میکردم نمیدونم چرا براش شما این مشکل پیش اومده ولی ممکنه توی نسخه جدید اینطور شده باشه

برای Query هم توی پروژه آخری بهتون گفتم میتونید از QueryContext استفاده کنید که خیلی Query گرفتن راحت میشه

علی شاکری

منتظرم پروژه digilearn کامل بشه بعد ببینم

در کل میخاستم بدونم اگه کلا با دپر بخام بزنم چطوری میشه؟ابزار خاصی برای نوشتن کوئری های پیچیده نیست؟

محمد اشرافی

نه دیگه اگر بخواین Raw Sql استفاده کنید باید کد های SQL استفاده کنید

علی شاکری

ممنون استاد

برای ثبت پاسخ باید خود شوید