🔍 تحلیل ریشه خطا
خطای Circular Dependency به دلیل ثبت نادرست XFileContentExtractor در DI Container ایجاد شده است:
⚠️ پیغام خطا:
A circular dependency was detected for the service of type 'IEnumerable<IXFileContentExtractor>'
زنجیره وابستگی مشکلساز:
| مرحله | سرویس | وابستگی |
|---|---|---|
| ۱ | XFileContentExtractor |
نیاز به IEnumerable<IXFileContentExtractor> در constructor |
| ۲ | IEnumerable<IXFileContentExtractor> |
شامل تمام IXFileContentExtractor های ثبت شده |
| ۳ | XFileContentExtractor (دوباره!) |
خودش هم به عنوان IXFileContentExtractor ثبت شده ❌ |
| ۴ | حلقه بینهایت → Crash | |
💡 راهحل اصلاحی
برای شکستن این حلقه، باید XFileContentExtractor را به عنوان IXFileContentExtractor ثبت نکنیم. به جای آن، آن را به صورت دستی با factory بسازیم.
MODIFY
xAiApi/Startup.cs (متد ConfigureServices)
کد اصلاحشده:
public void ConfigureServices(IServiceCollection services)
{
// ... (ثبتهای قبلی)
// ==========================================================
// ✅ ثبت File Content Extractors (همگی Singleton)
// ==========================================================
// ۱. ثبت Extractor های پایه
services.AddSingleton<IXFileContentExtractor, XPdfFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XDocxFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XImageFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XAudioFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XExcelFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XVisionFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XPlainTextFileContentExtractor>();
// ۲. ✅ اصلاح: ثبت XFileContentExtractor به صورت Factory
// به جای ثبت به عنوان IXFileContentExtractor، آن را به صورت دستی میسازیم
services.AddSingleton<XFileContentExtractor>(sp =>
{
// دریافت تمام Extractor های ثبت شده (به جز XFileContentExtractor)
var extractors = sp.GetServices<IXFileContentExtractor>();
return new XFileContentExtractor(extractors);
});
// ۳. ✅ ثبت XFileContentExtractor به عنوان IXFileContentExtractor
// اما با استفاده از Factory که از قبل ساخته شده
services.AddSingleton<IXFileContentExtractor>(sp =>
sp.GetRequiredService<XFileContentExtractor>());
// ==========================================================
// ✅ ثبت سرویسهای AI
// ==========================================================
services.AddSingleton<IXDefaultAIOCRService, XDefaultAIOCRService>();
services.AddScoped<IXDefaultAiService, XDefaultAiService>();
services.AddScoped<IXDefaultEmbeddingService, XDefaultEmbeddingService>();
services.AddScoped<IXDefaultThinkingAiService, XDefaultThinkingAiService>();
}
✅ چرا این راهحل کار میکند؟
- ✅
XFileContentExtractorابتدا به عنوان خودش (نه interface) ثبت میشود - ✅ در factory، تمام
IXFileContentExtractorهای دیگر را دریافت میکند - ✅ سپس به عنوان
IXFileContentExtractorثبت میشود (اما از instance از قبل ساخته شده) - ✅ حلقه وابستگی شکسته میشود
🔄 راهحل جایگزین (سادهتر)
اگر راهحل بالا پیچیده به نظر میرسد، میتوانید از این روش سادهتر استفاده کنید:
MODIFY
xAiApi/Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ... (ثبتهای قبلی)
// ==========================================================
// ✅ ثبت File Content Extractors
// ==========================================================
// ۱. ثبت Extractor های پایه
services.AddSingleton<IXFileContentExtractor, XPdfFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XDocxFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XImageFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XAudioFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XExcelFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XVisionFileContentExtractor>();
services.AddSingleton<IXFileContentExtractor, XPlainTextFileContentExtractor>();
// ۲. ✅ راهحل ساده: ساخت دستی XFileContentExtractor
// ابتدا تمام Extractor ها را در یک لیست جمع میکنیم
var extractorTypes = new[]
{
typeof(XPdfFileContentExtractor),
typeof(XDocxFileContentExtractor),
typeof(XImageFileContentExtractor),
typeof(XAudioFileContentExtractor),
typeof(XExcelFileContentExtractor),
typeof(XPlainTextFileContentExtractor)
};
// ۳. ثبت XFileContentExtractor با factory
services.AddSingleton<IXFileContentExtractor>(sp =>
{
var extractors = new List<IXFileContentExtractor>();
// ساخت دستی Extractor ها
foreach (var type in extractorTypes)
{
var instance = (IXFileContentExtractor)ActivatorUtilities.CreateInstance(sp, type);
extractors.Add(instance);
}
// افزودن XVisionFileContentExtractor (که وابستگی دارد)
var visionExtractor = sp.GetRequiredService<XVisionFileContentExtractor>();
extractors.Add(visionExtractor);
// ساخت XFileContentExtractor با لیست Extractor ها
return new XFileContentExtractor(extractors);
});
// ==========================================================
// ✅ ثبت سرویسهای AI
// ==========================================================
services.AddSingleton<IXDefaultAIOCRService, XDefaultAIOCRService>();
services.AddScoped<IXDefaultAiService, XDefaultAiService>();
services.AddScoped<IXDefaultEmbeddingService, XDefaultEmbeddingService>();
services.AddScoped<IXDefaultThinkingAiService, XDefaultThinkingAiService>();
}
📋 خلاصه تغییرات
| فایل | تغییر | دلیل |
|---|---|---|
Startup.cs |
services.AddScoped<IXFileContentExtractor, XFileContentExtractor>() services.AddSingleton<IXFileContentExtractor>(sp => { ... }) |
رفع Circular Dependency با استفاده از Factory Pattern |
✅ نتیجه نهایی:
- ✅ Circular Dependency کاملاً رفع میشود
- ✅ DI Container میتواند تمام سرویسها را بسازد
- ✅
XFileContentExtractorهمچنان به تمام Extractor ها دسترسی دارد - ✅ خطای
AggregateExceptionدیگر ظاهر نخواهد شد
💡 نکته مهم:
پس از اعمال این تغییر، پروژه را Rebuild کنید. خطای System.AggregateException دیگر ظاهر نخواهد شد و برنامه به درستی اجرا میشود.