У нас есть система регистрационного типа, которая отправляет подтверждение по электронной почте после завершения. В течение нескольких минут система имела около 3000 регистраций, и мы заметили ошибку. Если пользователь A регистрирует несколько мс после регистрации пользователем B, пользователь A получит данные пользователя B по электронной почте. Нам удалось решить проблему, и я сузил ее до этого фрагмента кода, который получает шаблон электронной почты из кеша, и просто заменяет строку на держателе места.Weird C# ошибка при замене текстовой строки
private string ProcessEmailBody(MyRegistrationModel registration)
{
var content = CacheHelper.GetContent("REGISTRATIONEMAIL");
if (content != null)
{
content.Text = context.Text.Replace("@@[email protected]@", registration.FullName);
return content.Text;
}
else return null;
}
Метод CacheHelper.GetContent()
является статическим, и я это исправил «ошибку», делая это:
private string ProcessEmailBody(MyRegistrationModel registration)
{
var content = CacheHelper.GetContent("REGISTRATIONEMAIL");
if (content != null)
{
string body = content.Text;
body = body.Replace("@@[email protected]@", registration.FullName);
return body;
}
else return null;
}
И я не могу понять, за жизнь мне, почему это исправили проблему. Может ли кто-нибудь пролить свет на это?
EDIT: Вот мой метод GetContent() (я знаю, что подписи отличаются выше, я был краток)
public static Content GetContent(string key, int partnerSiteId, int? version, IContentRepository contentRepository, out string cacheKey)
{
cacheKey = string.Format("{0}_{1}_{2}", key, partnerSiteId, version);
var content = CacheManager.Get(cacheKey,() => contentRepository.GetContent(key, partnerSiteId, version), WebConfig.GetCacheDuration(CacheProfile.Short));
return content;
}
private static DataCache _Cache = null; // DataCache is from AppFabric (Microsoft.ApplicationServer.Caching)
public static T Get<T>(string objectKey, Func<T> reloadItemExpresion, TimeSpan cacheDuration) where T : class
{
if (_Cache == null)
{
if (reloadItemExpresion != null)
{
return reloadItemExpresion.Invoke();
}
return null;
}
object cachedObject = null;
try
{
cachedObject = _Cache.Get(objectKey);
}
catch (Exception ex)
{
if (ex is FileNotFoundException)
{
_Cache.Remove(objectKey);
}
}
if (cachedObject != null)
{
return cachedObject as T;
}
if (reloadItemExpresion != null && cacheDuration > TimeSpan.Zero)
{
T item = reloadItemExpresion.Invoke();
if (item != null)
{
Insert(item, objectKey, cacheDuration);
}
return item;
}
return null;
}
contentRepository.GetContent
просто уходит в базу данных и получает фактическое содержание обратно.
Вывести код 'CacheHelper.GetContent' ... Скорее всего, он предоставляет экземпляры * shared * среди нескольких потоков, поэтому вы создаете условие гонки при изменении' content.Text'. –
Недостаточно информации; каков фактический тип 'content'?Как реализуется метод GetContent? Вы всегда раздаете один и тот же экземпляр 'content'? Поддерживает ли этот код многопоточность? В этом случае это может быть просто условие гонки, и вам необходимо обеспечить правильную синхронизацию потоков. –
Я отредактировал свой вопрос. – eth0