
یکی از دردسرها در هر پروژه ای تبدیل حروف ي و ك عربی به فارسیه. من برای حل این مشکل راه های مختلفی رو امتحان کردم. از Override كردن متدهای read و write مربوط به newtonsoft و اضافه کردن attribute به property های string بگیر تا استفاده از model binding و interceptor و .... .
تمام این روش ها جواب می دهند و هر کدام به نحوی مشکل را حل می کنند اما مزایا و معایب خودشون رو دارند. یکی از مشکلاتی که من داشتم این بود که با وجود استفاده از Ef Core در پروژه، بعضی از کوئری های پیچیده به صورت sql نوشته و با ExecuteReaderSqlAsync اجرا شده بودند.
بنابراین یکی از مشکلات در روش جایگزینی ي و ك عربی با فارسی در NET. با استفاده از Interceptor این است که ممکن است از Raw SQL یا Stored Procedure استفاده شده باشد. این کوئری ها مسلما از Command Interceptor عبور نمی کنند و قابل رهگیری و تغییر برای ما نیستند.
از طرفی کوئری هایی که با EF Core نوشته شده اند هم در صورتی که از ()AsNoTracking استفاده شده باشه تغییرات روی موجودیت ها ردیابی نمی شوند و اگر ()EnableSensitiveDataLogging رو فعال بکنید کوئری های مربوط به Update در لاگ ها ظاهر نمیشه و خود این مشکل هم باعث میشه که یه سری از ورودی ها رو از دست بدیم و نتونیم ي و ك عربی رو به فارسی تبدیل کنیم.
پس از کلی تست و درگیری و بررسی بالاخره به این نتیجه رسیدم که بهترین راه برای تبدیل ي و ك عربی به فارسی در NET. این هست که از یک Middleware استفاده کنم و Body تمام ریکوئست هایی که از نوع application/json هستند رو با استفاده از Buffering بررسی کنم و در صورت وجود ي و ك عربی اون ها رو به ی و ک فارسی تبدیل کنم. اینجوری تمام ورودی ها به صورت صحیح وارد برنامه و در نهایت در دیتابیس ذخیره می شوند و دیگه نیازی به اضافه کردن attribute به پراپرتی مدل ها نداریم و اگر از Raw SQL یا Stored Procedure هم استفاده شده باشه یا در ef از ()AsNoTracking استفاده شده باشه هیچ مشکلی به وجود نمیاد چون تمام درخواست ها قبل از اینکه به کنترلر برسند اصلاح شده اند.
در ادامه کد مربوط به YekeMiddleware رو قرار میدم
public class YekeMiddleware
{
private readonly RequestDelegate _next;
public YekeMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.ContentType != null && context.Request.ContentType.Contains("application/json"))
{
context.Request.EnableBuffering();
using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, leaveOpen: true))
{
var body = await reader.ReadToEndAsync();
body = body.Replace("ي", "ی").Replace("ك", "ک");
context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(body));
}
}
await _next(context);
}
}