edirectory read custom property value Unknown error (0x8000500c) - directoryservices

Strange things happen...
I was forced to move to a new developer machine (Windows Server 2008 R2 to 2012).
The exact same code doesn't work on the new machine.
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
MembershipUserCollection retvalue = new MembershipUserCollection();
string ldapConnectionString = _configuration.GetConnectionString();
using (DirectoryEntry de
= new DirectoryEntry(ldapConnectionString, _configuration.SearchAccount, _configuration.SearchAccountPassword, AuthenticationTypes.ServerBind))
{
string filter = string.Format("(&(objectClass=Person)(CUSTOMemail={0}))", emailToMatch);
DirectorySearcher ds = new DirectorySearcher(de, filter, new[] { "cn", "CUSTOMemail" }, SearchScope.Subtree);
SearchResultCollection collection = ds.FindAll();
totalRecords = collection.Count;
int pagesCount = (totalRecords > pageSize) ? (int)Math.Ceiling((double)(totalRecords / pageSize)) : 1;
if (pageIndex > pagesCount - 1)
throw new IndexOutOfRangeException("PageIndex exceeds max PageIndex");
for (int i = pageIndex * pageSize; i < totalRecords; i++)
{
DirectoryEntry userDirectoryEntry = collection[i].GetDirectoryEntry();
string userName = userDirectoryEntry.Properties["cn"].Value as string;
string providerUserKey = userDirectoryEntry.Path;
string email = userDirectoryEntry.Properties["CUSTOMemail"].Value as string;
MembershipUser mu = new MembershipUser(
providerName: Name,
name: userName,
providerUserKey: providerUserKey,
email: email,
passwordQuestion: null,
comment: null,
isApproved: true,
isLockedOut: false,
creationDate: DateTime.MinValue,
lastLoginDate: DateTime.MinValue,
lastActivityDate: DateTime.MinValue,
lastPasswordChangedDate: DateTime.MinValue,
lastLockoutDate: DateTime.MinValue);
retvalue.Add(mu);
}
}
return retvalue;
}
The code fails when it is trying to read the CUSTOMemail property. System properties (such as "cn") work.
The IIS settings are exactly the same although this shouldn't matter as the binding process works. The domain membership (I read various threads about that) didn't change and does not matter because it's an edirectory and I'm using a dedicated user to bind anyway.
I can filter on the property (see above) and view all the properties' names. A network trace shows me that the properties and their values are transmitted over the wire so everything I need is there. And using an LDAP explorer like JXplorer shows me the complete DirectoryEntry (including values).. however my C# code doesn't get along with it. I'm absolutely puzzled as to why it works on one virtual machine and not on the other one.
I'm intrigued by the fact that all the data is transmitted over the wire (so the directory definitely has no permissions issues here) but my C# code is unable to extract the values out of it :(

I know this is an old question, but since I busted my brains about the same thing for a bit, I figured its worthwhile for anyone who's gotten this far...
The problem lies in the way DirectoryServices caches the schema, if it attempts to load a custom attribute (any attribute not familiar to DirectoryServices via the domain its connected to)
(hotfix specifically for Windows 8/2012)
Its actually documented in a KB article
http://support.microsoft.com/kb/2802148 that also includes the hotfix that should solve your problem (if you haven't solved it already)

Is it possible this runs as a different user on the two different VM's? In which case a possible permissions issue? Does your user on the second VM has sufficient permissions?

Related

FluentMigrator create password protected SqlLite DB

I use FluentMigrator to create a SqlLite DB in C# using FluentMigrator.Runner.MigrationRunner. I wonder is there any way to use the SetPassword command o the SqlConnection only when the DB needs to be created ? There's a SqLiteRunnerContextFactory object but it don't seem to be a property that I can use to specify password.
public MigrationRunner CreateMigrationRunner(string connectionString, string[] migrationTargets, Assembly assembly, long version)
{
var announcer = new TextWriterAnnouncer(Console.WriteLine) { ShowSql = true };
var options = new ProcessorOptions { PreviewOnly = false, Timeout = 60 };
var runnerContext = new SqLiteRunnerContextFactory().CreateRunnerContext(connectionString, migrationTargets, version, announcer);
var sqlLiteConnection = new SQLiteConnection(connectionString);
//If the DB has already been created, it crashes later on if I specify this
sqlLiteConnection.SetPassword("ban4an4");
return new MigrationRunner(assembly,
runnerContext,
new SQLiteProcessor(sqlLiteConnection,
new SQLiteGenerator(),
announcer,
options,
new SQLiteDbFactory()));
}
I would like to avoid having to look if the file exists before setting password on connection.
Well, finally the code below works perfectly by using SetPassword everytime you create de runner. No need to check if the file exists or not. First time it creates it with the password and second time it opens it with it seems to use it to open DB. Which is exactly what I was looking for.

New item added to session on every request

I found this behaviour by accident, as I return the count of items in a session in an error message and found that some sessions had as many as 120 items in them (they should have 1!). On further investigation I found that every request seems to add an item into the session. They are all negative integers, like -710, -140 -528. I can't seem to see a pattern in what number comes up.
I have checked my code for any interactions with the Session object and as far as I can tell it is not me. I store one item in the session which is my own object which has a number of other properties on it. My session state is SQL server, and I am only serialising a certain set of values that need to be kept.
Has anyone seen anything like this or has any advice on where I can troubleshoot further?
Thank you in advance.
-- Edit, as requested - first where I count the items in the session - this is done in the page load event of my master page. I loop through so I could inspect using the debugger.
int itemCount = Session.Count;
for (int i = 0; i < itemCount; i++)
{
object o = Session[i];
}
-- here is where I add my custom object to the session. This is called at session start and in my master page. It runs on a "get, but if not there, create" principle.
HttpSessionState Session = HttpContext.Current.Session;
HttpRequest Request = HttpContext.Current.Request;
if (Session == null)
return null;
SessionData sessionData = (SessionData)Session[StaticNames.SESSION_NAME];
if (sessionData == null)
{
sessionData = new SessionData();
Session.Add(StaticNames.SESSION_NAME, sessionData);
}
I also have this to get the SessionData object from the session:
public SessionData(SerializationInfo info, StreamingContext ctxt)
{
this.IsManualLogin = (bool)info.GetValue("IsManualLogin", typeof(bool));
this.HasAskedUserForLocation = (bool)info.GetValue("HasAskedUserForLocation", typeof(bool));
// ... etc, more items for all users here
int? loginID = null;
try
{
loginID = info.GetInt32("LoginID");
}
catch
{
return;
}
this.LoginID = loginID.Value;
// ... etc, more items for logged in users only
}
There is also an equivalent method for adding this data to the SerializationInfo used for SqlSessionState.
Credit to the modest jadarnel27.
It turns out the Ajax Control Toolkit NoBot control adds an integer into your session on every request. My website has an auto 40 second refresh, similar to facebook, so this probably would have brought the whole thing crashing down at some point and I am lucky to find it now. Should anyone else consider using the NoBot control, be warned about this behaviour!

Error inside web service in Linq query I guess

While calling out web service method I get error as follow:
GenericException
An unexpected error occured.
Value cannot be null.
Parameter name: source
at System.Linq.Enumerable.Where[TSource](IEnumerable1 source, Func2 predicate)
at QuotingGate.CalcsLV.Casco.Standard.Ergo.Calculate(VehicleQuotingParameters parameters, CascoQuote& quote) in c:\Projects\xxx\WebServices\QuotingGate\CalcsLV\Casco\Standard\Ergo.cs:line 152
at QuotingGate.CalcsBase.CalculatorBase`4.Quote(In parameters) in c:\Projects\xxx\WebServices\QuotingGate\CalcsBase\Base.cs:line 138
On Ergo.cs line 152 there is linq query like that:
var territory = from c in prices.premiums where c.tariffParam3 == "LV" select c;
Googled and find many cases where there was Single instead of SingleOrDefault.. but in my case its linq and relay does not matter is there any result or not, right ?
Prices are set here :
...
policyDataKASKORetParam1 prices = null;
prices = ws.GetCascoQuotesUnregistered(quote,
parameters.Vehicle.VIN,
parameters.Vehicle.Make,
parameters.Vehicle.Model,
parameters.Vehicle.ManufactureDate.Value.Year,
parameters.Vehicle.Value.Value,
parameters.Vehicle.EngineCapacity ?? 0,
parameters.Insurance.StartDate.Value,
parameters.Insurance.Currency.ToString(), irJaunakLiet, parameters.Client.Code, parameters.Vehicle.OwnerCode, irDefinetieServisi);
enter code here
...
and the method it calls:
public policyDataKASKORetParam1 GetCascoQuotesUnregistered(CascoQuote quote, string vin, string make, string model, int year, int vehicleValue, int engine, DateTime policyStartDate, string currency, bool irJaunakLiet, string clientCode, string ownerCode, bool irDefinetieServisi)
{
policyDataKASKORetParam1 prices;
string personCode = string.IsNullOrWhiteSpace(Config.FixedOwnerCode) ? clientCode : Config.FixedOwnerCode;
DateTime start = policyStartDate;
DateTime issue = DateTime.Today;
prices = WS.getOfferDataKASKO(SessionKey,
personCode, // Holder Code
null,
null,
vin,
make,
model, // Model
year, // Year
engine, // Engine
string.Empty, // Usage
ownerCode, // Person Code
true,
false,
false,
false,
false,
false,
true,
false,
irJaunakLiet,
false,
irDefinetieServisi,
false, // TODO: All risks
(double)vehicleValue,
currency,
issue,
start,
null,
0d,
null,
null);
if (prices.status != 0)
quote.ErrorList.Add(new QuoteBase.Error(Errors.InsurerError, string.Format("Error message: {0}", prices.statusText)));
return prices;
}
Basically the last method calls out Web Service method.. So all together can i assume that the Web service dose not return me anything or can there be some other possibility's why it ends up null. (Don't know how to debug it, its running on remote server.. tried WCF tracing but without any results.. )
The Problem is in another country and business people are telling me that All the Web service should work so they are saying me that prices.premiums are not null.. but without debugging, cant really argue with them. Should i make a some kinda Client to run the Web Service and run it on my local machine ? Or is there some kinda another possibility to see the values of running instance ?
Also they say that Web Service hasn't been changed - also i know 100% that my code has not been changed, and all that worked fine like 10 days ago..
(PS I'm Junior who's mentor has left.. ~4 month experiences only )
From MSDN, here's the signature of the Where extension method:
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
As you can see, source is the parameter that corresponds to the collection and your error message indicates 'Parameter name: source' so my guess is that prices.premiums is null.

Cannot acces users Active Directory password information on production server

I'm developing an MVC application and I have a routine that gets the currently logged on users password info and it works fine on my PC but when I publish my application to a live server on the domain, I don't seem to be able to gain access to the AD information. I have used very similar code in a currently running asp.net web application and it works just fine. I compared security settings on both applications and they look identical. Here is the routine:
public int GetPasswordExpiration()
{
PrincipalContext domain = new PrincipalContext(ContextType.Domain);
string currUserName = WindowsIdentity.GetCurrent().Name;
UserPrincipal currLogin = UserPrincipal.FindByIdentity(domain, currUserName);
DateTime passwordLastSet = currLogin.LastPasswordSet.Value; //here is where it chokes***
int doyPasswordSet = passwordLastSet.DayOfYear;
int doy = DateTime.Today.DayOfYear;
int daysSinceLastset = (doy - doyPasswordSet);
int daysTilDue = (120 - daysSinceLastset);
return (daysTilDue);
}
I am an administrator on the domain so I think I have an application permissions issue, but since the failing application has the same permissions as the working application, I'm not sure where to look next. Any help is appreciated.
I'm answernig my own question because I want to post the code that works. Wiktor Zychla nailed it when asking if WindowsIdentity.GetCurrent().Name applied to the identity of the application pool rather than the logged in user. As a matter of fact it did, thanks Wiktor!
Here is the modified code that works. I did change the way I got the users identity (explained why below).
Controller Code:
using MyProject.Utilities; // Folder where I created the CommonFunctions.cs Class
var cf = new CommonFunctions();
string user = User.Identity.Name;
ViewBag.PasswordExpires = cf.GetPasswordExpiration(user);
Code in CommonFunctions
public int GetPasswordExpiration(string user)
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal currLogin = UserPrincipal.FindByIdentity(ctx, user);
DateTime passwordLastSet = currLogin.LastPasswordSet.Value;
int doyPasswordSet = passwordLastSet.DayOfYear;
int doy = DateTime.Today.DayOfYear;
int daysSinceLastset = (doy - doyPasswordSet);
int daysTilDue = (120 - daysSinceLastset);
return (daysTilDue);
}
The one thing that clued me in was that I decided to just run all the code in my controller and when I did, I got a red squiggly saying "The name WindowsIdentity does not exist in this context":
string currUserName = WindowsIdentity.GetCurrent().Name;
Also, the reason I retrieved User.Identity.Name in the Controller and passed it to the function is because once I got things working and wanted to thin out my controller, I tried to get User.Identity.Name in the function but I got another red squiggly with the same message under User in this line:
string user = User.Identity.Name;
So I figure this is a .net thing and just went with getting the User.Identiy.Name in the controller, pass it to the function and all is well. This one really tested my patience and I hope this post can help someone else.

Fill a word document in asp.net?

I am working on Asp.Net project which needs to fill in a word document. My client provides a word template with last name, firstname, birth date,etc... . I have all those information in the sql database, and the client want the users of the application be able to download the word document with filled in information from the database.
What's the best way to archive this? Basically, I need identify those "fillable spot" in word document, fill those information in when the application user clicks on the download button.
If you can use Office 2007 the way to go is to use the Open XML API to format the documents:
http://support.microsoft.com/kb/257757. The reason you have to go that route is that you can't really use Word Automation in a server environment. (you CAN, but it's a huge pain to get working properly, and can EASILY break).
If you can't go the 2007 route, I've actually had pretty good success with just opening up a word template as a stream and finding and replacing the tokens and serving that to the user. This has actually worked surprisingly well in my experience and it's REALLY simple to implement.
I'm not sure about some of the ASP.Net aspects, but I am working on something similar and you might want to look into using an RTF instead. You can use pattern replacement in the RTF. For example you can add a tag like {USER_FIRST_NAME} in the RTF document. When the user clicks the download button, your application can take the information from the database and replace every instance of {USER_FIRST_NAME} with the data from the database. I am currently doing this with PHP and it works great. Word will open the RTF without a problem so that is another reason I chose this method.
I have used Aspose.Words for .NET. It's a little on the pricey side, but it works extremely well and the API is fairly intuitive for something that is potentially very complex.
If you want to pre-design your documents (or allow others to do that for you), anyone can put fields into the document. Aspose can open the document, find and fill the fields, and save a new filled-out copy for download.
Aspose works okay, but again: it's pricey.
Definitely avoid Office Automation in web apps as much as possible. It just doesn't scale well.
My preferred solution for this kind of problem is xml: specifically here I recommend WordProcessingML. You create an Xml document according to the schema, put a .doc extension on it, and MS Word will open it as if it were native in any version as far back as Office XP. This supports most Word features, and this way you can safely reduce the problem to replacing tokens in a text stream.
Be careful googling for more information on this: there's a lot of confusion between this and new Xml-based format for Office 2007. They're not the same thing.
This code works for WordMl text boxes and checkboxes. It's index based, so just pass in an array of strings for all textboxes and an array of bool's for all checkboxes.
public void FillInFields(
Stream sourceStream,
Stream destinationStream,
bool[] pageCheckboxFields,
string[] pageTextFields
) {
StreamUtil.Copy(sourceStream, destinationStream);
sourceStream.Close();
destinationStream.Seek(0, SeekOrigin.Begin);
Package package = Package.Open(destinationStream, FileMode.Open, FileAccess.ReadWrite);
Uri uri = new Uri("/word/document.xml", UriKind.Relative);
PackagePart packagePart = package.GetPart(uri);
Stream documentPart = packagePart.GetStream(FileMode.Open, FileAccess.ReadWrite);
XmlReader xmlReader = XmlReader.Create(documentPart);
XDocument xdocument = XDocument.Load(xmlReader);
List<XElement> textBookmarksList = xdocument
.Descendants(w + "fldChar")
.Where(e => (e.AttributeOrDefault(w + "fldCharType") ?? "") == "separate")
.ToList();
var textBookmarks = textBookmarksList.Select(e => new WordMlTextField(w, e, textBookmarksList.IndexOf(e)));
List<XElement> checkboxBookmarksList = xdocument
.Descendants(w + "checkBox")
.ToList();
IEnumerable<WordMlCheckboxField> checkboxBookmarks = checkboxBookmarksList
.Select(e => new WordMlCheckboxField(w, e, checkboxBookmarksList.IndexOf(e)));
for (int i = 0; i < pageTextFields.Length; i++) {
string value = pageTextFields[i];
if (!String.IsNullOrEmpty(value))
SetWordMlElement(textBookmarks, i, value);
}
for (int i = 0; i < pageCheckboxFields.Length; i++) {
bool value = pageCheckboxFields[i];
SetWordMlElement(checkboxBookmarks, i, value);
}
PackagePart newPart = packagePart;
StreamWriter streamWriter = new StreamWriter(newPart.GetStream(FileMode.Create, FileAccess.Write));
XmlWriter xmlWriter = XmlWriter.Create(streamWriter);
if (xmlWriter == null) throw new Exception("Could not open an XmlWriter to 4311Blank-1.docx.");
xdocument.Save(xmlWriter);
xmlWriter.Close();
streamWriter.Close();
package.Flush();
destinationStream.Seek(0, SeekOrigin.Begin);
}
private class WordMlTextField {
public int? Index { get; set; }
public XElement TextElement { get; set; }
public WordMlTextField(XNamespace ns, XObject element, int index) {
Index = index;
XElement parent = element.Parent;
if (parent == null) throw new NicException("fldChar must have a parent.");
if (parent.Name != ns + "r") {
log.Warn("Expected parent of fldChar to be a run for fldChar at position '" + Index + "'");
return;
}
var nextSibling = parent.ElementsAfterSelf().First();
if (nextSibling.Name != ns + "r") {
log.Warn("Expected a 'r' element after the parent of fldChar at position = " + Index);
return;
}
var text = nextSibling.Element(ns + "t");
if (text == null) {
log.Warn("Expected a 't' element inside the 'r' element after the parent of fldChar at position = " + Index);
}
TextElement = text;
}
}
private class WordMlCheckboxField {
public int? Index { get; set; }
public XElement CheckedElement { get; set; }
public readonly XNamespace _ns;
public WordMlCheckboxField(XNamespace ns, XContainer checkBoxElement, int index) {
_ns = ns;
Index = index;
XElement checkedElement = checkBoxElement.Elements(ns + "checked").FirstOrDefault();
if (checkedElement == null) {
checkedElement = new XElement(ns + "checked", new XAttribute(ns + "val", "0"));
checkBoxElement.Add(checkedElement);
}
CheckedElement = checkedElement;
}
public static void Copy(Stream readStream, Stream writeStream) {
const int Length = 256;
Byte[] buffer = new Byte[Length];
int bytesRead = readStream.Read(buffer, 0, Length);
// write the required bytes
while (bytesRead > 0) {
writeStream.Write(buffer, 0, bytesRead);
bytesRead = readStream.Read(buffer, 0, Length);
}
readStream.Flush();
writeStream.Flush();
}
In general you are going to want to avoid doing Office automation on a sever, and Microsoft has even stated that it is a bad idea as well. However, the technique that I generally use is the Office Open XML that was noted by aquinas. It does take a bit of time to learn your way around the format, but it is well worth it once you do as you don't have to worry about some of the issues involved with Office automation (e.g. processes hanging).
Awhile back I answered a similar question to this that you might find useful, you can find it here.
If you need to do this in DOC files (as opposed to DOCX), then the OpenXML SDK won't help you.
Also, just want to add another +1 about the danger of automating the Office apps on servers. You will run into problems with scale - I guarantee it.
To add another reference to a third-party tool that can be used to solve your problem:
http://www.officewriter.com
OfficeWriter lets you control docs with a full API, or a template-based approach (like what your requirement is) that basically lets you open, bind, and save DOC and DOCX in scenarios like this with little code.
Could you not use Microsofts own InterOp Framework to utilise Word Functionality
See Here

Resources