Sunday, April 3, 2011

Cannot reinitialize subscriptions of non-immediate_sync publications.

while I was trying to solve the above issue, I came across to this useful page:

http://ashwin4all1.wordpress.com/2009/06/11/replication/

Thanks for sharing~

Monday, January 10, 2011

An alternative approach to TreeView for displaying and selecting active directory OU structure using infopath form

I was trying to figure out a way to show AD tree structure inside Infopath form without much luck. The reason for doing this is to put it into our new staff form so we can designate the OU where the new staff will be created so we can automate it in our biztalk process.

Anyway, instead of trying to show the whole tree structure, I came up with a workaround which is much easier while still achieving the same result.

the core component here is a web service to get the list of sub OUs by supplying a parent OU DSN, here is the source code for the web service:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Xml;
using System.DirectoryServices;

/// <summary>
/// Summary description for GetADChildNodesWS
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
// [System.Web.Script.Services.ScriptService]
public class GetADChildNodesWS : System.Web.Services.WebService
{

    public GetADChildNodesWS()
    {

        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }

    [WebMethod]
    public System.Xml.XmlDocument getADChildNodes(string dsnpath)
    {

        XmlDocument xmlnodes = new XmlDocument();
		if (dsnpath == "" || dsnpath ==null)
			dsnpath = "LDAP://DC=mycompany,DC=com";
		
        string updsnpath = dsnpath.Replace("LDAP://", "");
        if (updsnpath.Substring(0, 3).Equals("OU="))
            updsnpath = "LDAP://" + updsnpath.Substring(updsnpath.IndexOf(',')+1, updsnpath.Length - updsnpath.IndexOf(',')-1);
        else
            updsnpath = "LDAP://DC=mycompany,DC=com";
        string xmlstring = "<OU><SUBOU><name>Up one Level</name><value>" + updsnpath + "</value></SUBOU>";
        DirectoryEntry entry = new DirectoryEntry(dsnpath);

        entry.Username = "username";
        entry.Password = "pass";


        DirectorySearcher searcher = new DirectorySearcher(entry);
        searcher.Filter = "(ObjectClass=organizationalUnit)";
        searcher.PropertiesToLoad.Add("OU");
        searcher.SearchScope = SearchScope.OneLevel;
        SearchResultCollection resultColl = searcher.FindAll();

        if (resultColl.Count > 0)
        {
            foreach (SearchResult result in resultColl)
            {
                xmlstring += "<SUBOU>" + "<name>" + result.Properties["OU"][0].ToString() + "</name><value>" + "LDAP://OU=" + result.Properties["OU"][0].ToString() + "," + dsnpath.Replace("LDAP://", "") +
                    "</value></SUBOU>";
            }
            xmlstring += "</OU>";
            xmlnodes.LoadXml(xmlstring);
            return xmlnodes;

        }

        return null;
    }
}


once the web service is deployed, you then simply add a dropdown list to the infopath form, configure the drodown to get choice from an external data source which is the web service call.

Add a rule to the drodown with condition as the field is present, add two actions within the rule, one to set the query field value, another one to "query for data".

the way it works here is biz different, you need to keep clicking the same dropdown list untill you reach the OU from your root node, you can also navigate back by clicking on 'Up one Level' item, also select the empty option brings you back to the root level directly.

Sunday, January 9, 2011

Using Missing Index Information to Write CREATE INDEX Statements

Use the following guidelines for ordering columns in the CREATE INDEX statements you write from the missing indexes feature component output:

*List the equality columns first (leftmost in the column list).
*List the inequality columns after the equality columns (to the right of equality columns listed).
*List the include columns in the INCLUDE clause of the CREATE INDEX statement.
*To determine an effective order for the equality columns, order them based on their selectivity; that is, list the most selective columns first.


source: http://msdn.microsoft.com/en-us/library/ms345405.aspx

Thursday, December 16, 2010

BizTalk: combing two xml message into one

I ran into the situation where I need to combine two messages into one while developing a BizTalk App for Active Directory Integration.
I used SQL typedpooling to get updates of user information from datebase which contains userID and its Manager's ID as well as some other basic user information (comes from Epicor E4SE), since the Active Directory Adapter I was testing only support using DSN to update manager field of AD user, I have to run a AD query first to the the manager's distinguishedName from AD thus the need to combine them into the final Active Update schema.

Inside BizTalk, you select two messages as input and one destination schema as output in a map, let's say the final input is as below:

 <root>  
 <input1>  
 <ManagerID>ABC02</ManagerID>  
 </Input1>  
 <input2>  
 <ad>  
 <filtermatch ObjectPath="LDAP://CN=B\, Miss,OU=Finance,DC=subs,DC=mycompany,DC=com">  
 <property Name="sAMAccountName" Value="ABC01" />  
 <property Name="distinguishedName" Value="CN=B\, Miss,OU=Finance,DC=subs,DC=mycompany,DC=com" />  
 </FilterMatch>  
 <filtermatch ObjectPath="LDAP://CN=B\, Sir,OU=IT Dept,ODC=subs,DC=mycompany,DC=com">  
 <property Name="sAMAccountName" Value="ABC02" />  
 <property Name="distinguishedName" Value="CN=A\, Sir,OU=IT Dept,DC=subs,DC=mycompany,DC=com" />  
 </FilterMatch>  
 </AD>  
 </Input2>  
 </Root>  

the final custom xsl will be as below:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">  
 <xsl:output method="xml"/>  
 <xsl:template match="/">  
 <xsl:apply-templates />   
 </xsl:template>  
 <xsl:template match="/">  
 <dsn>  
 <xsl:variable name="Manager" select="Root/Input1/ManagerID/text()" />  
 <xsl:value-of select="Root/Input2/AD/FilterMatch[Property[@Name='sAMAccountName' and @Value=$Manager]][1]/Property[@Name='distinguishedName']/@Value" />  
 </DSN>  
 </xsl:template>  
 </xsl:stylesheet>  

Please note that normally the AD query will only returns 1 record, the reason I put more than one here is to experiment a bit and try to think of the way to handle choosing the right node based on the 'Master' xml input.

The key here is to use a xsl:variable to hold the Key field and use it in the xpath for matching up Xml Node.

So far I have managed to integrate Active Directory, our ERP system (Epicor E4SE) and infopath form together to achieve the 'single point of truth' for user records in a pilot. will write more about details sometime later.

Monday, November 15, 2010

Update List Column Programmatically for SharePoint 2007

Two ways of doing this:

First one is via SharePoint object model:


SPList oList = oWeb.Lists["Technical"];
SPField myField = oList.Fields["Sub-tag"];
String schema = " xx ";
myField.SchemaXml = schema;
myField.Update();


the Second way is via Lists.asmx web service:

XmlNode listNode = mylistsrv.GetList("Technical");
string version = listNode.Attributes["Version"].Value;
string guid = listNode.Attributes["Name"].Value;

XmlDocument xmlDoc = new XmlDocument();
XmlElement updateFields = xmlDoc.CreateElement("Fields");

string fieldXml = "";

updateFields.InnerXml = fieldXml;
XmlNode result = mylistsrv.UpdateList(guid, null, null, updateFields, null, version);

Disable Microsoft Defender for Cloud for Visual Studio Subscription (MSDN)

I use a visual studio pro subscription which comes with $150 azure cloud credit, for some reason Microsoft Defender for Cloud was turned on ...