开发者

Nested try-catches or is there a better way?

In the method below there are numerous case statements (many have been removed) that make calls to Manager classes. For example, the first one calls ApplicationManager.GetByGUID. Any time a "manager" class is used, security checks occur.

Problem: I have entities that may be permitted to some of these but not all. So when this method gets run, if one of them craps out it'll throw a security exception and crash the whole report.

Someone has suggested to me that I could just throw try-catch blocks around each case but the more I read the more I feel like that might be sloppy. I admittedly am not very knowledged about exceptions...I was hoping someone could suggest a way to do this with more finesse...I need to be able to get back good data and ignore the ones that throw security exceptions....or maybe try-catches are ok in this case?

Hope that makes sense...thanks


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);
                       开发者_JS百科         mconn.Close();
                                return reportLookups[type + value].ToString();
                            }


                        }

                        break;
                }
            }
            return string.Empty;
        }
    }
    finally 
    {
        mconn.Close();
    }
}


As a rule, Exceptions should indicate that something went wrong. If you're expecting exceptions during the course of a typical run through this method, you should change your APIs to allow you to avoid that exception:

if (mediaItemManager.CanAccessMediaItem(value))
{
    MediaItem mi = mediaItemManager.GetMediaItemByGUID(value);
    ....
}

Here's a quick attempt on my part to refactor this code into something more reasonable:

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;
    }
}

Since I don't understand the full scope of this code, I probably oversimplified some aspects of it, but you can see that there is a lot of refactoring to be done here. In the future, you might want to run some code by http://refactormycode.com/, until you get accustomed to using best practices.


Somewhere you will have some code like:

foreach(Request req in allRequests)
{
   Reply result = MakeReply(req);
   WriteReply(result);
}

Turn this into:

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);
}

You might want to put the try-catch into a separate function as the body of your foreach loop is getting large once you catch several types of exceptions.

StriplingWarrior is also right in his reply: "Exceptions should indicate that something went wrong." Let them propagate to the main loop and show them there.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜