Sharepoint - upgrade webpart properties - c#

I'm playing with SharePoint 2010 now and have a problem.
There is a feature that is responsible for webparts - it's scope is web. It's needed to update some properties of already created webparts, for example - title.
So I've overridden FeatureUpgrading event and added custom upgrade action into feature manifest - there is no problem here.
In that feature receiver I plan to have a code that should get the file with needed page, check it out, iterate through all the web parts on it, change property and then check in page back.
The problem is that all my webparts appear as ErrorWebPart with empty title.
By the way, if I use the same code in FeatureDeactivating event - everything works good.
The only difference I've noticed - in featureupgrading HttpContext.Current was null. So I've populated it manually but it didn't help.
While googling, the only two advices were: populate HttpContext and ensure that libs with webparts are in GAC. Both conditions are done in my situation.
The sample code from FeatureUpgrading is as proper:
SPUtility.ValidateFormDigest();
web.AllowUnsafeUpdates = true;
var request = new HttpRequest("", web.Url, "");
HttpContext.Current = new HttpContext(request, new HttpResponse(new StringWriter()));
HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
var fileUrl = web.Url + "/pages/sample.aspx";
var file = web.GetFile(fileUrl);
if (file.CheckOutType == SPFile.SPCheckOutType.None)
{
file.CheckOut();
}
using (var webPartsManager = file.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
foreach (WebPart webPart in webPartsManager.WebParts)
{
Console.WriteLine(webPart.GetType().ToString());
}
}
file.CheckIn("System update");
Would appreciate any help. Maybe there is something I'm missing or there is another variant to accomplish described task?
Regards.

Since it is working on Deactivating(), I think the order in which the features are activated is the problem.
You may have to ensure the below:
1. First activate the Feature that adds the webparts
2. Then activate the new feature.
You can change this in package. Or better add a dependency to your new feature.

Related

Sharepoint 2010 Programmatically Update List Item in Event Handler

Background
We have a custom developed installed .WSP on a SharePoint 2007 environment and have been in the process of upgrading to 2010. With the upgrade the custom event trigger no longer worked so trying to update and make it work in 2010. But I am running into one issue. Original developers no longer here and I've been the lucky one to have to figure this one out without much of a background with SP Dev.
Goal
When a new list item is created trigger event. Within event, create a shared folder using Item Name and return url, create a wiki-page using item name and include shared document link and return url to wiki page. Part three is update newly created list item with the New Folder url and Wiki Page URL.
Issue
I've gotten the first two parts working but so far have been unable to update the newly created list item with the new Links. I'm able to get the links. I've tried all the basic stuff for updating the list that I have been able to find online with no luck. Nothing to complicated(or so I think). But code is included below. VS is not installed on the server so unable to run debug mode, I don't have direct access to the server. When you create the item there are no client/user side error. Haven't been able to find a log file that has any, that is if it collects errors if the script were to fail out.
Initiation of the Event
public class CreateWikiAndFolder : Microsoft.SharePoint.SPItemEventReceiver
{
public override void ItemAdded(SPItemEventProperties properties)
{
try
{
//this.DisableEventFiring();
base.EventFiringEnabled = false;
string sUrlOfWikiPage = string.Empty;
string sUrlOfNewFolder = string.Empty;
string sSubsiteRUL = string.Empty;
string sCurrentItemTitle = properties.ListItem["Title"].ToString();
string sWikiListName = "TR Wikis";
string sDocLibName = "Shared Documents";
string sTRListID = "TR Status";
if (sTRListID.ToUpper().Equals(properties.ListTitle.ToString().ToUpper()))
{
//Create the Folder
sUrlOfNewFolder = CreateFolder(properties.ListItem.Web, sDocLibName, sCurrentItemTitle);
//Create the Wiki
string ItemDispFormUrl = String.Concat(properties.ListItem.Web.Url, "/", properties.ListItem.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url, "?ID=", properties.ListItem.ID.ToString());
sUrlOfWikiPage = CreateWiki(properties.ListItem.Web, sWikiListName, sCurrentItemTitle, ItemDispFormUrl, sUrlOfNewFolder);
//Update the current TR Item
//Have tried. properties.ListItem["WikiURL"] = sUrlOfWikiPage + ", " + "Wiki";
SPListItem myListItem = properties.ListItem;
SPFieldUrlValue shareFolderURLValue = new SPFieldUrlValue();
shareFolderURLValue.Description = "Shared Folder";
shareFolderURLValue.Url = sUrlOfNewFolder ;
myListItem["SharedFolder"] = shareFolderURLValue;
//I've tried each one separate and together to no luck
myListItem.UpdateOverwriteVersion();
myListItem.Update();
//properties.ListItem.UpdateOverwriteVersion();
}
base.EventFiringEnabled = true;
}
}
}
Note that this is the last thing needed to be figured out for our upgrade.
Got it working. I did both of these at the same time so I'm not sure if it was the combination of both or only one of the items. But one I removed the myListItem.UpdateOverwriteVersion(); line and surrounded the item updated with web.AllowUnsafeUpdates being set to true before and then back to false afterwards.
Also as a note to others, you need to save the properties.ListItem to its own SPListItem which you then update versus trying to manipulate the values at the properties.ListItem["Attribute"], and then update the properties.ListItem.Update. SharePoint doesn't allow the latter option so you have to save to an independent SPListItem, and then modify and update that one. This might not be the best SharePoint lingo, but that is what needs to be done.

How to find in VSPackage which version control system a solution uses

I'm new to extending Visual Studio and I'm trying to find way to find which source control system is used by current solution.
I created VsPackage project and I am able to obtain reference to solution via IVsSolution and to hook up to solution events via IVsSolutionEvents.
Inside OnAfterSolutionOpen (or possibly some other if there's an alternative) I would like to act differently basing on whether the solution uses TFS or Git or something else. How can I obtain this information?
I plan to support as many Visual Studio versions as possible, but if it isn't possible I would like to support at least VS2012 and higher.
Ok, after several hours of digging I've found a solution to this. Thanks to the article of Mark Rendle and the source code for his NoGit extension I've found, that the list of registered source control plugins is located in registry: HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\12.0_Config\SourceControlProviders (in case of VS 2013).
So now, we can have both plugin guid, and the name of the provider. This sample code can fetch those values:
var key = #"Software\Microsoft\VisualStudio\" + "12.0" + #"_Config\SourceControlProviders";
var subkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(key);
var providerNames = subkey.GetSubKeyNames().Dump();
var dict = new Dictionary<Guid, String>();
foreach (var provGuidString in subkey.GetSubKeyNames())
{
var provName = (string)subkey.OpenSubKey(provGuidString).GetValue("");
dict.Add(Guid.Parse(provGuidString), provName);
}
Now, there are two ways I've found to obtain guid of currently active provider.
important update: Apparently the second way of obtaining currently active plugin does not work as expected. I strongly advise using first solution.
This is the way that bases on the extension mentioned earlier:
var getProvider = GetService(typeof(IVsRegisterScciProvider)) as IVsGetScciProviderInterface;
Guid pGuid;
getProvider.GetSourceControlProviderID(out pGuid);
Or we can just go to HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\12.0\CurrentSourceControlProvider and get the default value of this key:
var key2 = #"Software\Microsoft\VisualStudio\12.0\CurrentSourceControlProvider";
var guidString = (string)Microsoft.Win32.Registry.CurrentUser.OpenSubKey(key2).GetValue("");
var currentGuid = Guid.Parse(guidString);
Now we just take var activeProviderName = dict[currentGuid]; and that's all.

Moving newly created publishing page to top in MOSS 2007 programmaticaly

I am stuck with this problem for nearly one day now:
In an application, I create a publishing page in code:
PublishingPage newPage = pages.Add(usableName, layout);
newPage.ListItem["Title"] = promoRecord.PromotionName;
newPage.ListItem["Description"] = string.Empty;
newPage.Update();
newPage.CheckIn("First draft");
So far so good. The problem is, I need the newly created page to appear at the top of the navigation. I was naive enough to think something as simple as this:
SPNavigationNodeCollection navigationNodes = pWeb.CurrentNavigationNodes;
SPNavigationNode newNode = null;
foreach (SPNavigationNode node in navigationNodes)
{
if (node.Url.Equals(prefix + newPage.Url, StringComparison.OrdinalIgnoreCase))
{
newNode = node;
}
}
newNode.MoveToFirst(navigationNodes);
would work. It doesn't, because the page is simply not there (in the CurrentNavigationNodes collection).
So I tried with:
newNode = new SPNavigationNode(promoRecord.PromotionName, prefix + newPage.Url);
navigationNodes.AddAsFirst(newNode);
with no luck either - here I got an exception saying that I can't add the page because it's in DRAFT state. Actually, the CurrentNavigation seems to get updated when I go to the frontend management (Manage Content And Structure / Site Administration / Navigation) - and the page appears there. Even if it's in DRAFT mode.
I tried a lot of things with no success... maybe you guys have an idea what I could try?
Thanks a lot in advance!

C# code completion with NRefactory 5

I just found out about NRefactory 5 and I would guess, that it is the most suitable solution for my current problem. At the moment I'm developing a little C# scripting application for which I would like to provide code completion. Until recently I've done this using the "Roslyn" project from Microsoft. But as the latest update of this project requires .Net Framework 4.5 I can't use this any more as I would like the app to run under Win XP as well. So I have to switch to another technology here.
My problem is not the compilation stuff. This can be done, with some more effort, by .Net CodeDomProvider as well. The problem ist the code completion stuff. As far as I know, NRefactory 5 provides everything that is required to provide code completion (parser, type system etc.) but I just can't figure out how to use it. I took a look at SharpDevelop source code but they don't use NRefactory 5 for code completion there, they only use it as decompiler. As I couldn't find an example on how to use it for code completion in the net as well I thought that I might find some help here.
The situation is as follows. I have one single file containing the script code. Actually it is not even a file but a string which I get from the editor control (by the way: I'm using AvalonEdit for this. Great editor!) and some assemblies that needs to get referenced. So, no solution files, no project files etc. just one string of source code and the assemblies.
I've taken a look at the Demo that comes with NRefactory 5 and the article on code project and got up with something like this:
var unresolvedTypeSystem = syntaxTree.ToTypeSystem();
IProjectContent pc = new CSharpProjectContent();
// Add parsed files to the type system
pc = pc.AddOrUpdateFiles(unresolvedTypeSystem);
// Add referenced assemblies:
pc = pc.AddAssemblyReferences(new CecilLoader().LoadAssemblyFile(
System.Reflection.Assembly.GetAssembly(typeof(Object)).Location));
My problem is that I have no clue on how to go on. I'm not even sure if it is the right approach to accomplish my goal. How to use the CSharpCompletionEngine? What else is required? etc. You see there are many things that are very unclear at the moment and I hope you can bring some light into this.
Thank you all very much in advance!
I've just compiled and example project that does C# code completion with AvalonEdit and NRefactory.
It can be found on Github here.
Take a look at method ICSharpCode.NRefactory.CSharp.CodeCompletion.CreateEngine. You need to create an instance of CSharpCompletionEngine and pass in the correct document and the resolvers. I managed to get it working for CTRL+Space compltition scenario. However I am having troubles with references to types that are in other namespaces. It looks like CSharpTypeResolveContext does not take into account the using namespace statements - If I resolve the references with CSharpAstResolver, they are resolved OK, but I am unable to correctly use this resolver in code completition scenario...
UPDATE #1:
I've just managed to get the working by obtaining resolver from unresolved fail.
Here is the snippet:
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
var resolver3 = unresolvedFile.GetResolver(cmp, loc); // get the resolver from unresolvedFile
var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );
Update #2:
Here is the complete method. It references classes from unit test projects, sou you would need to reference/copy them into your project:
public static IEnumerable<ICompletionData> DoCodeComplete(string editorText, int offset) // not the best way to put in the whole string every time
{
var doc = new ReadOnlyDocument(editorText);
var location = doc.GetLocation(offset);
string parsedText = editorText; // TODO: Why there are different values in test cases?
var syntaxTree = new CSharpParser().Parse(parsedText, "program.cs");
syntaxTree.Freeze();
var unresolvedFile = syntaxTree.ToTypeSystem();
var mb = new DefaultCompletionContextProvider(doc, unresolvedFile);
IProjectContent pctx = new CSharpProjectContent();
var refs = new List<IUnresolvedAssembly> { mscorlib.Value, systemCore.Value, systemAssembly.Value};
pctx = pctx.AddAssemblyReferences(refs);
pctx = pctx.AddOrUpdateFiles(unresolvedFile);
var cmp = pctx.CreateCompilation();
var resolver3 = unresolvedFile.GetResolver(cmp, location);
var engine = new CSharpCompletionEngine(doc, mb, new CodeCompletionBugTests.TestFactory(resolver3), pctx, resolver3.CurrentTypeResolveContext );
engine.EolMarker = Environment.NewLine;
engine.FormattingPolicy = FormattingOptionsFactory.CreateMono();
var data = engine.GetCompletionData(offset, controlSpace: false);
return data;
}
}
Hope it helps,
Matra
NRefactory 5 is being used in SharpDevelop 5. The source code for SharpDevelop 5 is currently available in the newNR branch on github. I would take a look at the CSharpCompletionBinding class which has code to display a completion list window using information from NRefactory's CSharpCompletionEngine.

How do I get latest clearcase label programmatically from C#?

I am trying to put version information to my C# GUI framework retrieved from the latest ClearCase label. This was originally done from Visual Soursafe as below.
vssDB = new VSSDatabaseClass();
vssDB.Open( databaseName, "vssadmin", "vssadmin" );
VSSItem item = vssDB.get_VSSItem( #"$\BuildDCP.bat", false );
foreach(VSSVersion vssVersion in item.get_Versions(0))
{
// Pull the first non-blank label and use that
if ( vssVersion.Label != "" )
{
labelID = vssVersion.Label.ToString();
break;
}
}
I am trying to do something similar using ClearCase since we changed our source code control from VSS to CC. Any help would be greatly appreciated.
Thanks!
I believe this could be better achieved through a script, which would be called from your C# program.
But you may be able to directly call some COM objects, through the CAL interface provided with ClearCase.
The documentation for the interface can be accessed through ClearCase help (Start>Programs>Rational ClearCase>ClearCase Help), where there's an entry for "ClearCase Automation Library (CAL)". An alternate path is to look in the ClearCase/bin directory for "cc_cal.chm".
In VB, with CAL API, that would give something like:
Dim CC As New ClearCase.Application
Dim labelID As String
Set aVersion = CC.Version("[Path-To]\BuildDCP.bat");
Set someLabels = Ver.Labels;
If (someLabels.Count > 0) Then
' the first label listed is the most recently applied
labelID = someLabels.Item(1).Type.Name
EndIf
I really wish that the COM interfaces had better documentation, or were more obvious. Or that the code to ClearCase Explorer or Project Explorer were open source.
I've done a few cool things, but I pretty much started by adding COM references to my C# project, and then started screwing around with the interfaces I found.
Good luck!

Categories

Resources