I am fetching custom properties from woorkbook using this method:
var wb = Globals.ThisAddIn.Application.Workbooks.Open(file.FullName);
wb.Windows[1].Visible = false;
if (wb != null)
{
foreach (var prop in wb.CustomDocumentProperties)
{
try
{
Console.WriteLine(prop.Name.ToString());
Console.WriteLine(prop.Value.ToString());
Properties.Add(new CustomDocumentProperty { Key = prop.Name.ToString(), Value = prop.Value.ToString() });
}
catch (Exception)
{
Console.WriteLine();
}
}
wb.Close(false);
}
This method works, but the problem is that it is really slow in fetching the properties before executing the loop. So is there any way to speed this up? I have tried to look at other posts on this site, but I havent seen anyone mention this issue. Please let me know if I need to post anymore code. (Properties is a list of a custom class)
Related
I am struggling to find the data type of AD attributes that are not having a value already.
Thus far a resulting DirecoryEntry only contains a property for attributes that already have a value. I can't find a method to obtain information about all other attributes.
Adding a value to the 'PropertiesToLoad' doesn't seem to do anything. The returned DirectoryEntry object contains all attributes (with values) regardless of what is added here.
Code used:
public void Test(string ldapPath)
{
Type orgType;
try
{
using (DirectoryEntry searchRoot = GetSearchRoot(ldapPath))
{
using (DirectorySearcher search = new DirectorySearcher(searchRoot))
{
search.Filter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=coen))";
search.PropertiesToLoad.Add("msExchHomeServerName");
SearchResult searchResult = search.FindOne();
{
using (DirectoryEntry entry = searchResult.GetDirectoryEntry())
{
if (entry != null)
{
if (entry.Properties.Contains("msExchHomeServerName"))
{
orgType = entry.Properties["msExchHomeServerName"].GetType();
}
else // The value is empty and NOT present in the current 'entry.Properties' object.
{
throw new Exception("Unknown type");
}
}
}
}
}
}
}
catch (Exception e)
{
<handle exception>
}
}
Is there a way to find the data type of the 'msExchHomeServerName' (or any of the 'empty' attributes) attribute?
Any help would be highly appreciated!
Coen
Active Directory has a schema. Obvious to say, not obvious to think about since, by default, you cannot explore it.
However, you can Register the Active Directory Schema MMC Snap-In1 and then, in a fresh instance of MMC, add that Snap-In.
This then allows you to explore the Classes and Attributes that make up your current AD schema (and add new classes/attributes if you know what you're doing and choose to do so).
msExchHomeServerName can then be discovered to be a "Unicode String", which means a plain string from C# should be acceptable. Note also that some types (particularly numeric ones) may also specify Minimums and Maximums which should be observed.
You can also explore the schema programatically via the ActiveDirectorySchema class, by e.g. calling ActiveDirectorySchema.GetCurrentSchema(); and then explore from there.
1I cannot remember if you need to have installed the general Domain Admin tools (such as Users and Computers) in order for that DLL to exist on your system.
Thanks to Damien_The_Unbeliever who pointed me in the right direction, I managed to create the following method:
public Dictionary<string, ActiveDirectorySyntax> GetAttributeSyntaxes(List<string> lstAttributeNames)
{
Dictionary<string, ActiveDirectorySyntax> dictRes = new Dictionary<string, ActiveDirectorySyntax>();
if (lstAttributeNames.Count > 0)
{
DirectoryContext directoryContext = new DirectoryContext(DirectoryContextType.DirectoryServer,
m_Server, m_UserName, m_Password);
using (ActiveDirectorySchema currentSchema = ActiveDirectorySchema.GetSchema(directoryContext))
{
using (ActiveDirectorySchemaClass objClass = currentSchema.FindClass("user"))
{
if (objClass != null)
{
ReadOnlyActiveDirectorySchemaPropertyCollection propcol = objClass.GetAllProperties();
foreach (ActiveDirectorySchemaProperty schemaProperty in propcol)
{
foreach (string attrName in lstAttributeNames)
{
if (schemaProperty.Name.Equals(attrName))
{
dictRes.Add(attrName, schemaProperty.Syntax);
break;
}
}
}
}
}
}
}
return dictRes;
}
The returned 'schemaProperty.Syntax' contains sufficient information to determine the actual data type.
Thanks Damien!
Background Info: I'm using an ItemCheckedIn receiver in SharePoint 2010, targeting .NET 3.5 Framework. The goal of the receiver is to:
Make sure the properties (columns) of the page match the data in a Content Editor WebPart on the page so that the page can be found in a search using Filter web parts. The pages are automatically generated, so barring any errors they are guaranteed to fit the expected format.
If there is a mismatch, check out the page, fix the properties, then check it back in.
I've kept the receiver from falling into an infinite check-in/check-out loop, although right now it's a very clumsy fix that I'm trying to work on. However, right now I can't work on it because I'm getting a DisconnectedContext error whenever I hit the UpdatePage function:
public override void ItemCheckedIn(SPItemEventProperties properties)
{
// If the main page or machine information is being checked in, do nothing
if (properties.AfterUrl.Contains("home") || properties.AfterUrl.Contains("machines")) return;
// Otherwise make sure that the page properties reflect any changes that may have been made
using (SPSite site = new SPSite("http://san1web.net.jbtc.com/sites/depts/VPC/"))
using (SPWeb web = site.OpenWeb())
{
SPFile page = web.GetFile(properties.AfterUrl);
// Make sure the event receiver doesn't get called infinitely by checking version history
...
UpdatePage(page);
}
}
private static void UpdatePage(SPFile page)
{
bool checkOut = false;
var th = new Thread(() =>
{
using (WebBrowser wb = new WebBrowser())
using (SPLimitedWebPartManager manager = page.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
// Get web part's contents into HtmlDocument
ContentEditorWebPart cewp = (ContentEditorWebPart)manager.WebParts[0];
HtmlDocument htmlDoc;
wb.Navigate("about:blank");
htmlDoc = wb.Document;
htmlDoc.OpenNew(true);
htmlDoc.Write(cewp.Content.InnerText);
foreach (var prop in props)
{
// Check that each property matches the information on the page
string element;
try
{
element = htmlDoc.GetElementById(prop).InnerText;
}
catch (NullReferenceException)
{
break;
}
if (!element.Equals(page.GetProperty(prop).ToString()))
{
if (!prop.Contains("Request"))
{
checkOut = true;
break;
}
else if (!element.Equals(page.GetProperty(prop).ToString().Split(' ')[0]))
{
checkOut = true;
break;
}
}
}
if (!checkOut) return;
// If there was a mismatch, check the page out and fix the properties
page.CheckOut();
foreach (var prop in props)
{
page.SetProperty(prop, htmlDoc.GetElementById(prop).InnerText);
page.Item[prop] = htmlDoc.GetElementById(prop).InnerText;
try
{
page.Update();
}
catch
{
page.SetProperty(prop, Convert.ToDateTime(htmlDoc.GetElementById(prop).InnerText).AddDays(1));
page.Item[prop] = Convert.ToDateTime(htmlDoc.GetElementById(prop).InnerText).AddDays(1);
page.Update();
}
}
page.CheckIn("");
}
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
From what I understand, using a WebBrowser is the only way to fill an HtmlDocument in this version of .NET, so that's why I have to use this thread.
In addition, I've done some reading and it looks like the DisconnectedContext error has to do with threading and COM, which are subjects I know next to nothing about. What can I do to prevent/fix this error?
EDIT
As #Yevgeniy.Chernobrivets pointed out in the comments, I could insert an editable field bound to the page column and not worry about parsing any html, but because the current page layout uses an HTML table within a Content Editor WebPart, where this kind of field wouldn't work properly, I'd need to make a new page layout and rebuild my solution from the bottom up, which I would really rather avoid.
I'd also like to avoid downloading anything, as the company I work for normally doesn't allow the use of unapproved software.
You shouldn't do html parsing with WebBrowser class which is part of Windows Forms and is not suited for web as well as for pure html parsing. Try using some html parser like HtmlAgilityPack instead.
Im trying to make a process where I unpack a set of rar-files using SharpCompress and then delete them.
I first have a foreach loop which loops over the different set of files to be unpacked like this:
foreach (var package in extractionPackages.Where(package => Extractor.ExtractToFolder(package, destinationFolder)))
{
FileHelper.DeleteExtractionFiles(package);
}
The extraction process is taken straight of the SharpCompress Tests code and goes like this:
public static bool ExtractToFolder(ExtractionPackage extractionPackage, string extractionPath)
{
var fullExtractionPath = Path.Combine(extractionPath, extractionPackage.FolderName);
try
{
using (var reader = RarReader.Open(extractionPackage.ExtractionFiles.Select(p => File.OpenRead(p.FullPath))))
{
while (reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(fullExtractionPath, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
return true;
}
catch (Exception)
{
return false;
}
}
As you can see in the first code block I then call to delete the files but there I recieve an error due to that the files are locked by another process:
The process cannot access the file 'file.rar' because it is being used by another process.
If I try to put the deletion after the foreach-loop I am able to delete all but the last set of files if there are more than one. If it is just one the same issue occurs since the last set of files doesn't seems to be "unlocked".
How can I structure the code so that the files is unlocked?
By using an example from Nunrar and modifying it a bit I finally seems to have solved the issue:
public static bool ExtractToFolder(ExtractionPackage extractionPackage, string extractionPath)
{
var fullExtractionPath = Path.Combine(extractionPath, extractionPackage.FolderName);
try
{
using (var reader = RarReader.Open(GetStreams(extractionPackage)))//extractionPackage.ExtractionFiles.Select(p => File.OpenRead(p.FullPath)), Options.None))
{
while (reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(fullExtractionPath, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
return true;
}
catch (Exception)
{
return false;
}
}
private static IEnumerable<Stream> GetStreams(ExtractionPackage package)
{
foreach (var item in package.ExtractionFiles)
{
using (Stream input = File.OpenRead(item.FullPath))
{
yield return input;
}
}
}
By default (and probably a flaw) is that I leave the Streams open as I did not create them myself. However, the .NET framework usually breaks this rule with things like StreamReader etc. so it's expected that they'd be closed.
I'm thinking I'm going to change this behavior. In the meantime, you ought to be able to fix this yourself by calling this:
RarReader.Open(extractionPackage.ExtractionFiles.Select(p => File.OpenRead(p.FullPath)), Options.None)
I had a similar trouble. I used SharpCompress for adding files in archive and I need to delete files after archiving. I had tried wrap streams with using() {} - but this solution didn't worked in my case. When I added to my code Application.DoEvents() - it solved the problem.
First off.. I am new to asp.net and EF.
I have an EntityDatsource on my page I would like to loop through each row in the result set.
My goal is to dynamically build a page based on the values in the result set. Then to post the information back after it is edited by the user. My plan was to iterate each row on the page_load event. Currently I just have p-code in the area I would like to make this happen. The p-code is as follows
// foreach (DataRow row in AvailableDeviceConfigDataSource.enti Rows)
// {
// if sectionHeading <> lastSectionHeading
// {
// lastSectionHeading = sectionHeading
// AddSettingsSection(sectionHeading)
// }
// AddRowObjects
// }
Any guidance would be much appreciated.
In case anybody comes across this and is interested, I did solve my issue a while ago and figured I should post my answer for the benefit of others....
using (var context = new MyEntities())
{
string lastSectionHeading = "";
bool isFirstHeading = true;
var dynamicPageItems = context.view_dynamicPageItems;
foreach (var item in dynamicPageItems)
{
if (item.IsActive == 1)
{
if (!lastSectionHeading.Equals(item.CategoryId))
{
if (!isFirstHeading)
CloseSection();
lastSectionHeading = item.CategoryId;
AddSettingsSection(item.CategoryDescription);
isFirstHeading = false;
}
AddControl( item.DataType );
}
}
}
(1) var list1 = web.GetList("/lists/list1");
(2) var item1 = list1.GetItemById(10001);
(3) ...
take breakpoint here, open item with ID = 10001 for edit, change 'Title' fields and save it. Then run code follow:
(4)item1[SPBuiltInFieldId.Title] = "some text";
(5)item1.Update();
row (5) throws save conflict exception.
How can to lock item for edit at line (3)? Or any other approach to avoid conflict?
You have to check the SPListItem manually
try
{
var item = list.GetItemById(3);
item["MyField"] = "FooBar";
item.Update();
}
catch(SPException conflictEx)
{
// handle conflict by re-evaluating SPListItem
var item = list.GetItemById(3);
// ..
}
I don't know any other mechanism atm.
// *create a new SPWeb object for each list modification otherwise
we'll get Save Conflict*
from the following URL
http://platinumdogs.me/2010/01/21/sharepoint-calling-splist-update-causes-save-conflict-spexception/
exceptions
using (var thisWeb = featSite.OpenWeb(featWeb.ID))
{
try
{
var listUpdate = false;
var theList = thisWeb.Lists[att.Value];
// change list configuration
// .....
// commit List modifications
if (listUpate)
theList.Update();
}
catch
{
// log the event and rethrow
throw;
}
}
}
}
Another approach is using Linq to SharePoint, Linq to SharePoint offers you a conflict resolution mechanism
SharePoint's LINQ provider is querying for concurrent changes when you try to save changes you've made using the SubmitChanges method.
When a conflict has been found, a ChangeConflictException will be thrown.
foreach(var notebook in spSite.Notebooks)
{
notebook.IsTopNotebook = true;
}
try
{
spSite.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch(ChangeConflictException ex)
{
foreach(ObjectChangeConflict occ in spSite.ChangeConflicts)
{
if (((Notebook)occ.Object).Memory > 16)
{
foreach (MemberChangeConflict field in occ.MemberConflicts)
{
if (field.Member.Name == "IsTopNotebook")
{
field.Resolve(RefreshMode.KeepCurrentValues);
}
else
{
field.Resolve(RefreshMode.OverwriteCurrentValues);
}
}
}
else
{
occ.Resolve(RefreshMode.KeepCurrentValues);
}
}
spSite.SubmitChanges();
}