在下面的方法中,有许多用于调用Manager类的case语句(许多已被删除)。例如,第一个调用ApplicationManager.GetByGUID。每次使用“manager”类时,都会进行安全检查。
问题:我有一些实体可能被允许使用其中一些但不是全部。因此,当这个方法运行时,如果其中一个方法崩溃,它将抛出安全异常并使整个报告崩溃。
有人告诉我,我可以在每个案例周围抛出try-catch块,但是我阅读的越多,我觉得这可能是草率的。我承认我对异常并不是很了解......我希望有人可以建议一种更精细的方法来做到这一点......我需要能够找回好的数据并忽略抛出安全异常的数据....或者在这种情况下尝试捕获可以吗?
希望有意义......谢谢
private string GetLookup(string value, string type)
{
MySqlConnection mconn = new MySqlConnection(ConfigurationSettings.AppSettings["UnicornConnectionString_SELECT"]);
try
{
mconn.Open();
lock (reportLookups)
{
if (reportLookups.ContainsKey(type+value))
return reportLookups[type+value].ToString();
else if (reportLookups.ContainsKey(value))
return reportLookups[value].ToString();
else
{
switch (type)
{
case "ATTR_APPLICATIONNAME":
if (value != Guid.Empty.ToString())
{
reportLookups.Add(type + value, applicationManager.GetByGUID(value).Name);
}
else
{
reportLookups.Add(type + value, "Unknown");
}
mconn.Close();
return reportLookups[type + value].ToString();
break;
case "ATTR_CITYNAME":
reportLookups.Add(type + value, UMConstantProvider.UMConstantProvider.GetConstant<UMString64>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.CITY_NAME, ref mconn));
mconn.Close();
return reportLookups[type + value].ToString();
break;
case "ATTR_COUNTRYNAME":
reportLookups.Add(type + value, UMConstantProvider.UMConstantProvider.GetConstant<UMString2>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.COUNTRY_NAME, ref mconn));
mconn.Close();
return reportLookups[type + value].ToString();
break;
case "ATTR_ITEMDURATION":
MediaItem mi = mediaItemManager.GetMediaItemByGUID(value);
if (mi.MediaItemTypeID == (int)MediaItemType.ExternalVideo || mi.MediaItemTypeID == (int)MediaItemType.ExternalAudio)
{
reportLookups.Add(type + value, mediaItemManager.GetMediaItemByGUID(value).ExternalDuration);
mconn.Close();
return reportLookups[type + value].ToString();
}
else
{
List<BinaryAsset> bins = fileSystemManager.GetBinaryAssetsByMediaItemGuid(value, mi.DraftVersion);
var durationasset = from d in bins
where d.Duration != 0
select d.Duration;
if (durationasset.Count() > 0)
{
reportLookups.Add(type + value, durationasset.ToList()[0]);
}
else
{
reportLookups.Add(type + value, 0);
mconn.Close();
return reportLookups[type + value].ToString();
}
}
break;
}
}
return string.Empty;
}
}
finally
{
mconn.Close();
}
}
答案 0 :(得分:3)
作为一项规则,例外情况应该表明出现了问题。如果您在通过此方法的典型运行过程中期望出现异常,则应更改API以避免该异常:
if (mediaItemManager.CanAccessMediaItem(value))
{
MediaItem mi = mediaItemManager.GetMediaItemByGUID(value);
....
}
我快速尝试将此代码重构为更合理的代码:
private string GetLookup(string value, string type)
{
var lookupKey = type + value;
using (MySqlConnection mconn = new MySqlConnection(ConfigurationSettings.AppSettings["UnicornConnectionString_SELECT"]))
{
mconn.Open();
lock (reportLookups)
{
if (reportLookups.ContainsKey(lookupKey))
{
return reportLookups[lookupKey].ToString();
}
var value = GetLookupValue(type, value);
reportLookups[lookupKey] = value;
return value;
}
}
}
private string GetLookupValue(string type, string value)
{
switch (type)
{
case "ATTR_APPLICATIONNAME":
return value == Guid.Empty.ToString()
? "Unknown"
: applicationManager.CanGetByGUID(value)
? applicationManager.GetByGUID(value).Name
: string.Empty;
case "ATTR_CITYNAME":
return UMConstantProvider.UMConstantProvider.GetConstant<UMString64>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.CITY_NAME, ref mconn);
case "ATTR_COUNTRYNAME":
return UMConstantProvider.UMConstantProvider.GetConstant<UMString2>(int.Parse(value), UMMetricsResourceLibrary.Enumerations.ConstantType.COUNTRY_NAME, ref mconn);
case "ATTR_ITEMDURATION":
if(mediaItemManager.CanGetMediaItemByGUID(value)) {
MediaItem mi = mediaItemManager.GetMediaItemByGUID(value);
if (mi.MediaItemTypeID == (int)MediaItemType.ExternalVideo || mi.MediaItemTypeID == (int)MediaItemType.ExternalAudio)
{
return mediaItemManager.GetMediaItemByGUID(value).ExternalDuration;
}
else
{
List<BinaryAsset> bins = fileSystemManager.GetBinaryAssetsByMediaItemGuid(value, mi.DraftVersion);
var durationasset = from d in bins
where d.Duration != 0
select d.Duration;
return durationasset.FirstOrDefault() ?? "0";
}
}
else
{
return string.Empty;
}
default:
return string.Empty;
}
}
由于我不理解这段代码的全部范围,我可能过度简化了它的某些方面,但你可以看到这里有很多重构要做。将来,您可能希望按http://refactormycode.com/运行一些代码,直到您习惯使用最佳实践。
答案 1 :(得分:0)
在某个地方你会得到一些代码:
foreach(Request req in allRequests)
{
Reply result = MakeReply(req);
WriteReply(result);
}
将其转换为:
foreach(Request req in allRequests)
{
Reply result;
try
{
result = CreateReply(req);
}
catch(SecurityException ex)
{
result = CreateReplyUnauthorized();
}
catch(Exception ex) // always the last
{
LogException(ex); // for bug hunting
// Don't show the exception to the user - that's a security risk
result = CreateReplySystemError();
}
WriteReply(result);
}
您可能希望将try-catch放入一个单独的函数中,因为一旦捕获到几种类型的异常,foreach循环的主体就会变大。
StriplingWarrior在他的回复中也是对的:“例外应该表明出了问题。”让它们传播到主循环并在那里显示它们。