Sharepoint SPDisposeCheck

The SPDisposeCheck utility warned me of an incorrectly located SPWeb.Add call. As you can see below, the usual method (SPWeb NewWeb = webs.add (siteUrl ....) will not work because RunWithElevatedPrivileges will make return newWeb out of context.

Having looked at the string newWeb = webs.Add () , can anyone suggest a way to correctly place the new SPWeb object? Thanks in advance.

public partial class SiteHelper { public static SPWeb CreateSiteFromSTP(SPWeb parentWeb, string newSiteSTP, int teamId) { try { SPWeb newWeb = null; SPSecurity.RunWithElevatedPrivileges(delegate() { string siteUrl = teamId.ToString(); SPWebCollection webs = parentWeb.Webs; newWeb = webs.Add(siteUrl,.,.,.,); TraceProvider.WriteLine("Activating Feature : MembersFeature "); newWeb.Features.Add(new Guid(TeamSiteAttributes.MembersFeature), true); TraceProvider.WriteLine("Activating Feature : BadgeAwardsFeature "); newWeb.Features.Add(new Guid(TeamSiteAttributes.BadgeAwardsFeature), true); TraceProvider.WriteLine("Activating Feature : ProjectBenefitsFeature "); newWeb.Features.Add(new Guid(TeamSiteAttributes.ProjectBenefitsFeature), true); TraceProvider.WriteLine("Activating Feature : TeamScoreFeature "); newWeb.Features.Add(new Guid(TeamSiteAttributes.TeamScoreFeature), true); newWeb.Update(); parentWeb.Update(); }); return newWeb; } catch (Exception ex) { TraceProvider.WriteLine("Error", ex); throw; } } } 
+4
source share
3 answers

SPDisposeCheck reports this as an error because it is not smart enough to know what you are doing with newWeb after you return it from this method. As long as you use NewWeb after calling CreateSiteFromSTP (), you will not have a memory leak.

If you are sure that you do not have a memory leak in this method, you can set SPDisposeCheck to ignore this warning. Just add the following declaration (with the correct SPDisposeCheckID you received) above the CreateSiteFromSTP method:

 [SPDisposeCheckIgnore(SPDisposeCheckID.SPDisposeCheckID_110, "Caller will dispose")] 
+6
source

This is basically a question of best practices for safe cleanup in this case ... would it be better if this method returned a GUID or url for a new SPWeb, rather than the actual SPWeb that was created? Thus, this method could correctly get rid of the SPWeb he created, and the caller would still have the opportunity to easily create another SPWeb, whose life is less mysterious. What is the real cost of creating SPWeb compared to the risk of going through one and potentially neglecting proper cleanup?

+1
source

The correct way to dispose of your new SPWeb is in the area where it was created. If you need to perform additional operations on your new website, just pass the call to the delegate:

 public static void CreateSiteFromSTP(SPWeb parentWeb, string newSiteSTP, int teamId, Action<SPWeb> actionOnCreate) { // ... using(var newWeb = webs.Add(...)) { // ... newWeb.Update(); actionOnCreate(newWeb); } } 

Then you can simply pass in a method (anonymous or named) that manages your new SPWeb , without responsibility for deletion. This approach also has the advantage that you are not returning SPWeb outside of your elevated block, which is unsupported and unreliable.

In fact, I would be surprised to find that your code really works the way you expect: existing SharePoint objects (in particular parentWeb ) have their permissions set when they were created, and also should not be transferred to an elevated context. The best approach for raising permissions in SharePoint is to use SPSite impersonation. Using the RunAsSystem method defined here , I would reorganize your code as follows:

 public static void ElevateToCreateSiteFromSTP(SPWeb parentWeb, string newSiteSTP, int teamId, Action<SPWeb> actionOnCreate) { parentWeb.RunAsSystem(elevWeb => CreateSiteFromSTP(elevWeb, newSiteSTP, teamId, actionOnCreate)); } private static void CreateSiteFromSTP(SPWeb parentWeb, string newSiteSTP, int teamId, Action<SPWeb> actionOnCreate) { try { string siteUrl = teamId.ToString(); SPWebCollection webs = parentWeb.Webs; using(var newWeb = webs.Add(siteUrl, ...)) { var newWebFeatures = newWeb.Features; TraceProvider.WriteLine("Activating Feature : MembersFeature "); newWebFeatures.Add(new Guid(TeamSiteAttributes.MembersFeature), true); TraceProvider.WriteLine("Activating Feature : BadgeAwardsFeature "); newWebFeatures.Add(new Guid(TeamSiteAttributes.BadgeAwardsFeature), true); TraceProvider.WriteLine("Activating Feature : ProjectBenefitsFeature "); newWebFeatures.Add(new Guid(TeamSiteAttributes.ProjectBenefitsFeature), true); TraceProvider.WriteLine("Activating Feature : TeamScoreFeature "); newWebFeatures.Add(new Guid(TeamSiteAttributes.TeamScoreFeature), true); newWeb.Update(); parentWeb.Update(); if(actionOnCreate != null) actionOnCreate(newWeb); } } catch (Exception ex) { TraceProvider.WriteLine("Error", ex); throw; } } 

This has the added benefit of decoupling your height problems from logic before creating SPWeb . I also prefer to do this very clearly when my code works with different resolutions.

+1
source

Source: https://habr.com/ru/post/1286422/


All Articles