Search
Extension method to Serialize/Deserialize MSCRM Entity
Email SSRS report using CRM SDK
/*Email SSRS report using CRM SDK.. -Add web reference in your project and set web reference url of your web service of ssrs e.g. http://10.1.4.83/ReportServer/ReportExecution2005.asmx -Add these references in your code editor. */ using Microsoft.Crm.Sdk; using Microsoft.Crm.SdkTypeProxy; using Microsoft.Crm.Sdk.Query; using MCS.Crm.emailssrs.ReportExecution; //MCS.Crm.emailssrs is project name using Microsoft.Win32; using System.Net; Write a function and add code below. public void SendSSRSReport() { string reportServiceUrl = "http://10.1.4.83/ReportServer/ReportExecution2005.asmx"; // Create the Report Service Url from the registry RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\MSCRM", false); if (key != null) { reportServiceUrl = (string)key.GetValue("SQLRSServerURL") + @"/ReportExecution2005.asmx"; } // Report parameter Name and Value fields are strings. ReportExecution.ParameterValue[] parameters = new ParameterValue[3]; parameters[0] = new ParameterValue(); parameters[0].Label = "RegistrationNumber"; parameters[0].Name = "RegistrationNumber"; parameters[0].Value = mcs_RegistrationNumber; parameters[1] = new ParameterValue(); parameters[1].Label = "FromDate"; parameters[1].Name = "FromDate"; parameters[1].Value = _fdate.ToShortDateString(); parameters[2] = new ParameterValue(); parameters[2].Label = "ToDate"; parameters[2].Name = "ToDate"; parameters[2].Value = _tdate.ToShortDateString(); string reportName = "myreport"; // Specify what type of report you want to create HTML,PDF, CVS, Excel, Word, XML, MHTML, Image string reportFormat = "PDF"; // Specify the device information to control the output of your report. //For device information See http://msdn2.microsoft.com/en-us/library/ms155397.aspx string deviceInformation = "2402400"; // Generate a report in a format for a CRM annotation or email attachment byte[] generatedReport = GenerateSRSbytes(reportName, parameters, reportFormat, deviceInformation, reportServiceUrl, null, null, null); string _str = Convert.ToBase64String(generatedReport); string FileName = "myreport.pdf"; string Subject = "Email SSRS Report "; mcsCrmService= new CrmService(); CrmAuthenticationToken token = new CrmAuthenticationToken(); token.AuthenticationType = 0; token.OrganizationName = "TestOrg"; mcsCrmService.Url ="http://10.1.4.83:5555/mscrmservices/2007/crmservice.asmx"; mcsCrmService.PreAuthenticate = true; mcsCrmService.CrmAuthenticationTokenValue = token; mcsCrmService.Credentials=System.Net.CredentialCache.DefaultCredentials; Guid _to = new Guid("e1b67b12-1e8a-4bb2-9c86-fdb8f75dda4d");//To email address GUID Guid _from = new Guid("a1e9c6a2-73e5-4117-a8c9-c15b89a92203");//From email address GUID // Create an activity party for the email activityparty party = new activityparty(); party.partyid = new Lookup(); party.partyid.type = EntityName.systemuser.ToString(); party.partyid.Value = _from; activityparty party2 = new activityparty(); party2.partyid = new Lookup(); party2.partyid.type = EntityName.account.ToString(); party2.partyid.Value = _to; //Create email template in CRM and get GUID of that template from Internet Explorer: Guid _templateid = new Guid("a783eea1-222b-461c-9c1f-e8185fd5504d");//template GUID InstantiateTemplateRequest _insTemplate = new InstantiateTemplateRequest();//Initialize template object. _insTemplate.TemplateId=_templateid; _insTemplate.ObjectId = (Guid)party2.partyid.Value; _insTemplate.ObjectType=party2.partyid.type; InstantiateTemplateResponse _tempResponse=(InstantiateTemplateResponse)mcsCrmService.Execute(_insTemplate); // Create an email message. email email = (email)_tempResponse.BusinessEntityCollection.BusinessEntities[0]; // Set email properties email.from = new activityparty[] { party }; email.to = new activityparty[] { party2 }; email.regardingobjectid = party2.partyid; email.subject = Subject ; email.directioncode = new CrmBoolean(true); Guid emailID = mcsCrmService.Create(email); attachment.activityid = new Lookup(); attachment.activityid.Value = emailID; attachment.activityid.type = EntityName.email.ToString(); attachment.filename = FileName; attachment.attachmentnumber = new CrmNumber(); attachment.body = _str; attachment.mimetype = @"application/pdf"; // Create the Attachment in CRM. Guid attachmentId = mcsCrmService.Create(attachment); //Send Email. SendEmailRequest _sendEmailReq = new SendEmailRequest(); _sendEmailReq.EmailId = emailID; _sendEmailReq.IssueSend = true; _sendEmailReq.TrackingToken = ""; mcsCrmService.Execute(_sendEmailReq); } public byte[] GenerateSRSbytes(string reportPath, ParameterValue[] parameters, string outputFormat, string deviceInformation, string ReportServiceUrl, string userName, string passWord, string domainName) { string encoding; string mimeType; string extension; string[] streamIDs; string SessionId; string historyID = null; Warning[] warnings; // By default the Report will run with the permissions of the AD authenticated User. ReportExecutionService rs = new ReportExecutionService(); rs.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials; rs.Url = ReportServiceUrl; // Impersonate credentials if they are specified. if (userName != null && passWord != null) { if (domainName == null) { rs.Credentials = new NetworkCredential(userName, passWord); } else { rs.Credentials = new NetworkCredential(userName, passWord, domainName); } } // Set timeout in seconds of the report takes a long time. rs.Timeout = 600000; ExecutionHeader execHeader = new ExecutionHeader(); rs.ExecutionHeaderValue = execHeader; ExecutionInfo execInfo = new ExecutionInfo(); execInfo = rs.LoadReport(reportPath, historyID); rs.SetExecutionParameters(parameters, "en-us"); SessionId = rs.ExecutionHeaderValue.ExecutionID; // Render Report return rs.Render(outputFormat, deviceInformation, out extension, out mimeType, out encoding, out warnings, out streamIDs); }
Create User in AD
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.DirectoryServices; using System.DirectoryServices.ActiveDirectory; using System.DirectoryServices.AccountManagement; namespace ActiveDirectory_User { class Program { // our User class public class User { // our user variables public string Firstname; public string Lastname; public string LoginId; public string Department; public string Office; public string EmailAddress; public bool IsDisabled; // Default constructor for our user object public User() { } // Custom constructor that takes a set of parameters and sets the respective variable - notice how I change // the variable from camelCase to PascalCase - this is how I program, you do not have to do this but do get in to a // habit of standardising your code variables public User(string firstName, string lastName, string loginId, string department, string office, string emailAddress) { Firstname = firstName; Lastname = lastName; LoginId = loginId; Department = department; Office = office; EmailAddress = emailAddress; } // user method one (CreateAccount) public bool CreateAccount() { // wrap our connection in a try catch block which will safeguard us against application crash if for example we can't connect to AD try { string FullPath = "LDAP://PLABDC01/ou=" + Department + ",dc=PRACTICELABS,dc=COM"; // Active directory connection DirectoryEntry Directory = new DirectoryEntry(FullPath, "Administrator", "Passw0rd"); // New user DirectoryEntry NewUser = Directory.Children.Add("CN=" + LoginId, "user"); // givenName is first name NewUser.Properties["givenName"].Value = Firstname; // sn is last name NewUser.Properties["sn"].Value = Lastname; // login id NewUser.Properties["sAMAccountName"].Value = LoginId; // office NewUser.Properties["physicalDeliveryOfficeName"].Value = Office; // commit the new user NewUser.CommitChanges(); // update the user to be enabled, here we CAST the value as an integer (i.e. we instruct the compiler that the return type value will be an int. // casting this will cause exceptions if the return type is not what you specify so beware! int val = (int)NewUser.Properties["userAccountControl"].Value; NewUser.Properties["userAccountControl"].Value = val & ~0x2; NewUser.CommitChanges(); // everything worked ok, return a value of true return true; } catch (Exception error) { // an error occured, write the error message out and return a value of false Console.Write("An error occured while creating user:{0} {1}: \n{2}", Firstname, Lastname, error.Message); return false; } } // user method that searches active directory to find our account and then disable it public bool DisableAccount() { // wrap our method in a try catch block in case it fails when we connect to AD or something try { // attach to AD DirectoryEntry Directory = new DirectoryEntry("LDAP://dc=PRACTICELABS,dc=COM"); // create an AD search object DirectorySearcher SearchAD = new DirectorySearcher(Directory); // add our filter which is our login id SearchAD.Filter = "(SAMAccountName=" + LoginId + ")"; SearchAD.CacheResults = false; // get the result SearchResult Result = SearchAD.FindOne(); Directory = Result.GetDirectoryEntry(); // if we get the result, disable the account and commit the changes Directory.Properties["userAccountControl"].Value = 0x0002; Directory.CommitChanges(); return true; } catch (Exception error) { // oh dear something went wrong, again write the error message out including the login id Console.WriteLine("An error occured when disabling this user:{0}\n{1}", LoginId, error.Message); return false; } } } static void Main(string[] args) { // create our OU's string[] Departments = { "Marketing", "Sales", "Human Resources" }; foreach (string dept in Departments) { CreateOU(dept); } // generate our random users - this populates AD ListMyRandomUsers = GenerateRandomUserAccounts(); // write our user information to the console so we can see the users that were created foreach (User u in MyRandomUsers) { Console.WriteLine((u.Firstname + " " + u.Lastname).PadRight(18, ' ') + u.Department.PadRight(18, ' ') + u.Office); } // disable every other account int Count = 0; foreach (User u in MyRandomUsers) { if (Count % 2 == 0) { if (u.DisableAccount()) { Console.WriteLine("Disabled: {0} {1} in department: {2}", u.Firstname, u.Lastname, u.Department); } else { Console.WriteLine("Failed to disable: {0} {1} in department: {2}", u.Firstname, u.Lastname, u.Department); } } Count++; } // this is an added function not explained in the tutorial, for more information see the explaination of the code beloew UpdateDisabled(MyRandomUsers); // write out the users (proves the update of the IsDisabled flag of the user object foreach (User u in MyRandomUsers) { if (u.IsDisabled) { Console.WriteLine("Account:{0} is disabled", u.LoginId); } } // wait for a keypress so everything doesnt disapear Console.ReadLine(); } public static void UpdateDisabled(List users) { Console.WriteLine("Updating disabled accounts"); foreach (User u in users) { try { DirectoryEntry Directory = new DirectoryEntry("LDAP://dc=PRACTICELABS,dc=COM"); DirectorySearcher Search = new DirectorySearcher(Directory); Search.Filter = "(SAMAccountName=" + u.LoginId + ")"; Search.CacheResults = false; SearchResult Result = Search.FindOne(); Directory = Result.GetDirectoryEntry(); object o = Directory.Properties["userAccountControl"].Value; // (514 = disabled) if ((int)Directory.Properties["userAccountControl"].Value == 514) { // this account is disabled u.IsDisabled = true; } else { // this account is not disabled u.IsDisabled = false; } } catch (Exception error) { Console.WriteLine("An error occured when disabling this user:{0}\n{1}", u.LoginId, error.Message); } } } public static void CreateOU(string ou) { try { if (!DirectoryEntry.Exists("LDAP://PLABDC01/ou=" + ou + ",dc=PRACTICELABS,dc=COM")) { try { DirectoryEntry ActiveDirectory = new DirectoryEntry("LDAP://PLABDC01/dc=PRACTICELABS,dc=COM", "Administrator", "Passw0rd"); DirectoryEntry NewOU = ActiveDirectory.Children.Add("OU=" + ou, "OrganizationalUnit"); NewOU.CommitChanges(); ActiveDirectory.CommitChanges(); Console.WriteLine("Created OU:{0}", ou); } catch (Exception error) { Console.WriteLine("An error occured while creating group:{0} :\n{1}", ou, error.Message); } } else { Console.WriteLine("OU already exists"); } } catch (Exception error) { Console.WriteLine("We couldnt connect to AD! Is the server powered on?. Exception generated was\n{0}", error.Message); } } public static List GenerateRandomUserAccounts() { List RandomUsers = new List (); string[] Firstnames = { "Bart", "Homer", "Maggie", "Marge", "Lisa", "Ned" }; // our firstname string[] Lastnames = { "Simpson", "Flanders", "Smith" }; // our lastname string[] Departments = { "Marketing", "Sales", "Human Resources" }; // our OU string[] Offices = { "London", "New York", "Hong Kong", "Japan" }; // our office Random RandomNumber = new Random(); foreach (string l in Lastnames) { foreach (string f in Firstnames) { int DepartmentId = RandomNumber.Next(0, Departments.Length); int OfficeId = RandomNumber.Next(0, Offices.Length); User NewUser = new User(f, l, f + "." + l, Departments[DepartmentId], Offices[OfficeId], f + "." + l + "@practicelabs.com"); RandomUsers.Add(NewUser); if (NewUser.CreateAccount()) { Console.WriteLine("Created user OK:" + f + " " + l); } } } return RandomUsers; } } }
Mouse Drag and Drop using C#
using System.Drawing; using System.Windows.Forms; namespace IndiLogix.MouseDrag { static class mouseDrag { private static Point mouse_offset; // Mouse Point Strut // Mouse Down Mouse Offset public static void mOffset(MouseEventArgs e) { mouse_offset = new Point(-e.X, -e.Y); } // Mouse Down Mouse Move public static void mMove(MouseEventArgs e,Form frm) { if (e.Button == MouseButtons.Left) { Point mousePos = Control.MousePosition; mousePos.Offset(mouse_offset.X, mouse_offset.Y); //this.Location = mousePos; frm.Location = mousePos; } } } }
Fake SMTP Server
using System; using System.Text; using System.Net; using System.Net.Sockets; using System.Threading; namespace Fake { public class SMTPServer { TcpClient client; NetworkStream stream; System.IO.StreamReader reader; System.IO.StreamWriter writer; public SMTPServer(TcpClient client) { this.client = client; stream = client.GetStream(); reader = new System.IO.StreamReader(stream); writer = new System.IO.StreamWriter(stream); writer.NewLine = "\r\n"; writer.AutoFlush = true; } static void Main(string[] args) { TcpListener listener = new TcpListener(IPAddress.Loopback,25); listener.Start(); while (true) { SMTPServer handler = new SMTPServer(listener.AcceptTcpClient()); Thread thread = new System.Threading.Thread(new ThreadStart(handler.Run)); thread.Start(); } } public void Run() { writer.WriteLine("220 localhost -- Fake proxy server"); for (string line = reader.ReadLine(); line != null; line = reader.ReadLine()) { Console.Error.WriteLine("Read line {0}", line); switch (line) { case "DATA": StringBuilder data = new StringBuilder(); String subject = ""; line = reader.ReadLine(); if (line != null && line != ".") { const string SUBJECT = "Subject: "; if (line.StartsWith(SUBJECT)) subject = line.Substring(SUBJECT.Length); else data.AppendLine(line); for (line = reader.ReadLine(); line != null && line != "."; line = reader.ReadLine()) { data.AppendLine(line); } } String message = data.ToString(); Console.Error.WriteLine("Received email with subject: {0} and message: {1}", subject, message); writer.WriteLine("250 OK"); client.Close(); return; default: writer.WriteLine("250 OK"); break; } } } } }
Chatbot using c#
Simple Encryption
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RedOF
{
class Program
{
public static string key;
public static int[] KeyArr = { 4,8,7,8};//4037//4878//7835
static void Main(string[] args)
{
Console.WriteLine("VCode ");
keygen();
WRITEKey();
string ans;
ans = @"Love the way you lie";
//ans= Console.ReadLine();
//Console.WriteLine("\n \nREDOF{0}: {1}",key,Encode(ans).ToUpper());
string qus = Encode(ans) + ":" + "RDF" + key;
Console.WriteLine(qus);
//Console.WriteLine("GOTKEY:{0}",GETKey(qus));
Console.WriteLine("{0}", Decode(qus));
//Encode("ggggg");
Console.Read();
}
//prints anything
static void prn(Object o)
{
Console.WriteLine(o);
}
//Gets the key from chipertext
static string GETKey(string chiper)
{
char[] hh = { '1', '2', '3', ' ' };
Console.WriteLine("Signature Index....{0}",chiper.IndexOf(":RDF", 1));
chiper.CopyTo(chiper.IndexOf(":RDF",1)+4, hh, 0, 4);
string res=null;
//Console.WriteLine("{0}{1}{2}{3}", hh[0], hh[1], hh[2], hh[3]);
foreach (char cc in hh)
res = res + cc;
return res;
}
//Writes the Key to the file
static void WRITEKey()
{
Console.Write("KEY:");
foreach (int t in KeyArr)
{
Console.Write(t);
key = key + t;
}
Console.Write("\n");
}
//Generated Random Key
static void keygen()
{
int rr;
Random rnd = new Random();
for (int i = 0; i < 3; i++)
{
rr = rnd.Next(1, 9);
KeyArr[i] = rr;
}
}
// Encodes the Plaintext
static string Encode(string plaintxt)
{
int tempnum,asc,i=0;
string tempchar=null;
foreach(char ch in plaintxt)
{
i++;
tempnum = Convert.ToInt32(ch);
asc = Convert.ToInt32(KeyArr[i % 4]) + tempnum;
tempchar = tempchar + Convert.ToChar(asc);
}
return tempchar;
}
//Decode.....
static string Decode(string chipertext)
{
int tempnum, asc, i = 0;
string tempchar = null;
foreach (char ch in chipertext)
{
if (i >=chipertext.Length-8)
{
i++;
}
else
{
i++;
tempnum = Convert.ToInt32(ch);
asc = tempnum - KeyArr[i % 4];
tempchar = tempchar + Convert.ToChar(asc);
}
}
return tempchar;
}
}
}
Hashtable
using System; using System.Collections; class Program { static void Main() { Hashtable table = new Hashtable(); table["one"] = 1; table["two"] = 2; // ... Print value at key. Console.WriteLine(table["one"]); } }
ArrayList in c#
using System; using System.Collections; class Program { static void Main() { ArrayList list = new ArrayList(); list.Add("cat"); list.Add(2); list.Add(false); foreach (var element in list) { Console.WriteLine(element); } } }
Dictionary
Dictionary is used when we have many different elements. We specify its key type and its value type. It provides good performance.
using System; using System.Collections.Generic; class Program { static void Main() { // Use the dictionary. DictionaryThe Dictionary type provides fast lookups with keys to get values. With it we use keys and values of any type, including ints and strings. Dictionary requires a special syntax form.dict = new Dictionary (); dict.Add("cat", 1); dict.Add("dog", 4); Console.WriteLine(dict["cat"]); Console.WriteLine(dict["dog"]); } }
Add
using System; using System.Collections.Generic; class Program { static void Main() { Dictionarydictionary = new Dictionary (); dictionary.Add("cat", 2); dictionary.Add("dog", 1); dictionary.Add("llama", 0); dictionary.Add("iguana", -1); } }
Get values
Next, you can check to see if a given string is present in a Dictionary with string keys. We look at more types of Dictionaries further on, but here is the ContainsKey method. It returns true if the key was found.using System; using System.Collections.Generic; class Program { static void Main() { Dictionarydictionary = new Dictionary (); dictionary.Add("apple", 1); dictionary.Add("windows", 5); // See whether Dictionary contains this string. if (dictionary.ContainsKey("apple")) { int value = dictionary["apple"]; Console.WriteLine(value); } // See whether Dictionary contains this string. if (!dictionary.ContainsKey("acorn")) { Console.WriteLine(false); } } }
KeyValuePair
When Dictionary, or any object that implements IDictionary, is used in a foreach-loop, it returns an enumeration. In the case of Dictionary, this enumeration is in the form of KeyValuePair values.
KeyValuePair stores two values together. It is a single generic struct. The KeyValuePair type in System.Collections.Generic is simple and always available. It is used internally in Dictionary and other collections.using System; using System.Collections.Generic; class Program { static void Main() { // Shows a List of KeyValuePairs. var list = new List>(); list.Add(new KeyValuePair ("Cat", 1)); list.Add(new KeyValuePair ("Dog", 2)); list.Add(new KeyValuePair ("Rabbit", 4)); foreach (var element in list) { Console.WriteLine(element); } } }
Often, you need to return two separate values from a method. You can do this easily with KeyValuePair. You must specify the exact type in the return value, and then return the new KeyValuePair in the method body.
using System; using System.Collections.Generic; class Program { static void Main() { Console.WriteLine(GetNames()); } static KeyValuePairGetNames() { // Gets collection of first and last name. string firstName = "William"; string lastName = "Gates"; return new KeyValuePair (firstName, lastName); } }
Implementation
You should know the basic layout of the KeyValuePair struct. Here, we see the internal code. The KeyValuePair has two private fields, and two public properties that retrieve the values of those fields.[Serializable, StructLayout(LayoutKind.Sequential)] public struct KeyValuePair{ private TKey key; private TValue value; public KeyValuePair(TKey key, TValue value); public TKey Key { get; } public TValue Value { get; } public override string ToString(); }
List
using System; using System.Collections.Generic; class Program { static void Main() { // Use the List type. Listlist = new List (); list.Add("cat"); list.Add("dog"); foreach (string element in list) { Console.WriteLine(element); } } }
Consuming CGI webService
FunccgiService = (xx_1,xx_2) =>
{
// Build Query URL
QueryUrl = "http://www.url.htm?xx1=" + xx_1 + "&xx2=" + xx_2;
// If required by the server, set the credentials.
WebRequest request = WebRequest.Create(QueryUrl);
request.Credentials = CredentialCache.DefaultCredentials;
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
//Response.Write(((HttpWebResponse)_response).StatusDescription);
// Get the stream containing content returned by the server.
Stream dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
if (dataStream != null)
{
StreamReader reader = new StreamReader(dataStream);
// Read the content.
ResponseFromServer = reader.ReadToEnd();
// Display the content.
//Response.Write(ResponseFromServer);
ResponseFromServer = ResponseFromServer.Substring(59, ResponseFromServer.Length - 59);
// Clean up the streams and the response.
reader.Close();
}
response.Close();
return ResponseFromServer;
};
// how to call
string result = cgiService("query1","query2");
parse url parameter in asp.net
This is how to get URL parameters in asp.net
//parse url parameter in asp.net
//EX: default.aspx?file= new file&query=search
string file = Request.QueryString["file"].ToString();
string query = Request.QueryString["query"].ToString();
Hope it helps
Query the Contents of Files
This example shows how to query over all the files in a specified directory tree, open each file, and inspect its contents. This type of technique could be used to create indexes or reverse indexes of the contents of a directory tree.
A simple string search is performed in this example.
class QueryContents
{
public static void Main()
{
// Modify this path as necessary.
string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";
// Take a snapshot of the file system.
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(startFolder);
// This method assumes that the application has discovery permissions
// for all folders under the specified path.
IEnumerablefileList = dir.GetFiles("*.*", System.IO.SearchOption.AllDirectories);
string searchTerm = @"Visual Studio";
// Search the contents of each file.
// A regular expression created with the RegEx class
// could be used instead of the Contains method.
// queryMatchingFiles is an IEnumerable.
var queryMatchingFiles =
from file in fileList
where file.Extension == ".htm"
let fileText = GetFileText(file.FullName)
where fileText.Contains(searchTerm)
select file.FullName;
// Execute the query.
Console.WriteLine("The term \"{0}\" was found in:", searchTerm);
foreach (string filename in queryMatchingFiles)
{
Console.WriteLine(filename);
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
// Read the contents of the file.
static string GetFileText(string name)
{
string fileContents = String.Empty;
// If the file has been deleted since we took
// the snapshot, ignore it and return the empty string.
if (System.IO.File.Exists(name))
{
fileContents = System.IO.File.ReadAllText(name);
}
return fileContents;
}
}
Intro to Linked Lists
Introduction
Like an array, a collection is a series of items of the same type. The particularity with creating an array is that you must know in advance the number of items that will make up the list. There are times when you don't know, you can't know, or you can't predict the number of items of the list. For this reason, you may want to create the list for which you don't specify the maximum number of items but you allow the user of the list to add, locate, or remove items at will. Such a list is referred to as a linked list.
Before creating a list, most of the time you would first decide or define what the list would be made of. As different as collections are, one list can be made of numeric values, such as a list that will be made of numbers. You may want a list that is made of names. Such a list can be created from a class that includes a string member variable. Another type of list can contain complex objects. In some other cases, at the time you are creating the collection class, you may not want to specify its type of items. In this case, you can create the class as generic.
Implementing a Collection
After deciding what each item of the list would be made of, you can create a class that would manage the list. This class would be responsible for all operations that can be performed on the list. If the list will be made of primitive values, you can directly create a field of the desired type. Here is an example:
//code section using System; public class Numbers { public double Number; } public class Exercise { static int Main(string[] args) { Numbers nbrs = new Numbers(); return 0; } }
If the list will be made of objects, you can first create a class that specifies those types of items and then declare its variable in the list class. Here is an example of a simple class that holds a double-precision value:
//code section using System; public class Number { public double Item; } public class Numbers { Number Sample; } public class Exercise { static int Main(string[] args) { Numbers nbrs = new Numbers(); return 0; } }
When creating a list, one of the aspects you should pay attention to is to keep track of the number of items in the list. To do this, you can create a property that holds the number. The value of this property would increase as the items are added to the list and the value would decrease as the items are removed from the list. Here is how this can be done:
//code section using System; public class Number { public double Item; } public class Numbers { int size; Number Sample; public Numbers() { size = 0; } public int Count { get { return size; } } } public class Exercise { static int Main(string[] args) { var nbrs = new Numbers(); Console.WriteLine("Number of Items: {0}", nbrs.Count); return 0; } }
This would produce: Number of Items: 0 Press any key to continue . . .
You can also create a Boolean read-only property that allows you to check whether the list is currently empty or not. When implementing the get accessor of this property, if the size of the list is 0, return true; otherwise, return false. This would be done as follows:
//code section using System; public class Number { public double Item; } public class Numbers { int size; Number Sample; public Numbers() { size = 0; } public int Count { get { return size; } } public bool IsEmpty { get { if (size == 0) return true; return false; } } }
CRM 2011 Processes
Processes - Introduction
Processes - Dialogs
Processes - Workflow
Processes - Performance & Versioning
Check if all upper case string
using System.Text.RegularExpressions; const string ALL_CAPS_PATTERN = "[a-z]"; static readonly Regex All_Caps_Regex = new Regex (ALL_CAPS_PATTERN); static bool AllUpperCase (string inputString) { if (All_Caps_Regex.IsMatch ( inputString )) { return false; } return true; }Below is another approach:
using System.Text.RegularExpressions; static bool AllCapitals(string inputString) { return Regex.IsMatch(inputString, @"^[A-Z]+$"); }
Find File by Extension
This example shows how to find all files that have a specified file name extension (for example ".txt") in a specified directory tree. It also shows how to return either the newest or oldest file in the tree based on the creation time.
class FindFileByExtension
{
// This query will produce the full path for all .txt files
// under the specified folder including subfolders.
// It orders the list according to the file name.
static void Main()
{
string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";
// Take a snapshot of the file system.
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(startFolder);
// This method assumes that the application has discovery permissions
// for all folders under the specified path.
IEnumerablefileList = dir.GetFiles("*.*", System.IO.SearchOption.AllDirectories);
//Create the query
IEnumerablefileQuery =
from file in fileList
where file.Extension == ".txt"
orderby file.Name
select file;
//Execute the query. This might write out a lot of files!
foreach (System.IO.FileInfo fi in fileQuery)
{
Console.WriteLine(fi.FullName);
}
// Create and execute a new query by using the previous
// query as a starting point. fileQuery is not
// executed again until the call to Last()
var newestFile =
(from file in fileQuery
orderby file.CreationTime
select new { file.FullName, file.CreationTime })
.Last();
Console.WriteLine("\r\nThe newest .txt file is {0}. Creation time: {1}",
newestFile.FullName, newestFile.CreationTime);
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
Regular expressions in C#
Regular fundamentals
It all starts with the idea of specifying a grammar for a particular set of strings. All you have to do is find a pattern that matches all of the strings you are interested in, and then use the pattern. The simplest sort of pattern is the string literal that matches itself. So, for example, if you want to process ISBN numbers you might well want to match the string “ISBN:” which is its own regular expression in the sense that the pattern “ISBN:” will match exactly one string of the form “ISBN:”. To actually use this you have to first create a Regex object with the regular expression built into it:Regex ex1 = new Regex(@"ISBN:");
The use of the “@” at the start of the string is optional, but it does make it easier when we start to use the “/” escape character. Recall that strings starting with “@” are represented “as is” without any additional processing or conversion by C#. To actually use the regular expression we need one of the methods offered by the Regex object. The Match method applies the expression to a specified string and returns a Match object. The Match object contains a range of useful properties and methods that let you track the operation of applying the regular expression to the string. For example, if there was a match the Success property is set to true as in:
MessageBox.Show( ex1.Match(@"ISBN: 978-1871962406"). Success.ToString());The index property gives the position of the match in the search string:
MessageBox.Show( ex1.Match(@"ISBN: 978-1871962406"). Index.ToString());
…which in this case returns zero to indicate that the match is at the start of the string. To return the actual match in the target string you can use the ToString method. Of course in this case the result is going to be identical to the regular expression but in general this isn’t the case. Notice that the Match method returns the first match to the regular expression and you can use the NextMatch method which returns another Match object.
Pattern matching
If this is all there was to regular expressions they wouldn’t be very interesting. The reason they are so useful is that you can specify patterns that spell out the regularities in a type of data.
For example following the ISBN: we expect to find a digit – any digit. This can be expressed as “ISBN:\d” where \d is character class indicator which means “a digit”. If you try this out you will discover that you don’t get a match with the example string because there is a space following the colon. However “ISBN:\s\d” does match as \s means “any white-space character” and:
Regex ex1 = new Regex(@"ISBN:\s\d"); MessageBox.Show( ex1.Match(@"ISBN: 978-1871962406"). ToString();
it…displays “ISBN: 9”. There’s a range of useful character classes and you can look them up in the documentation. The most useful are: aa5dd6a7065402ca9de1de54ec2685ee There is also the convention that capital letters match the inverse set of characters: 8626db14b952423a391096e21ae61f85 Notice that the inverse sets can behave unexpectedly unless you are very clear about what they mean. For example, \D also matches white space and hence:
…displays “ISBN: 9”. There’s a range of useful character classes and you can look them up in the documentation. The most useful are: aa5dd6a7065402ca9de1de54ec2685ee There is also the convention that capital letters match the inverse set of characters: 8626db14b952423a391096e21ae61f85 Notice that the inverse sets can behave unexpectedly unless you are very clear about what they mean. For example, \D also matches white space and hence:
@"ISBN:\D\d"…matches ISBN: 9. You can also make up your own character group by listing the set of characters between square brackets. So for example, [0-9] is the same as \d. Negating a character set is also possible and [^0-9] matches anything but the digits and is the same thing as \D. There are also character sets that refer to Unicode but these are obvious enough in use not to need additional explanation.
As well as characters and character sets you can also use location matches or anchors. For example, the ^ (caret) only matches the start of the string, and @”^ISBN:” will only match if the string starts with ISBN: and doesn’t match if the same substring occurs anywhere else. The most useful anchors are: 6e134837b27ec65df47860dbe2a5f7ba So for example:
@"^\d+$"…specifies a string consisting of nothing but digits. Compare this to
@"^\d*$"
…which would also accept a null string. One subtle point only emerges when you consider strings with line breaks. In this case by default the ^ and $ match only the very start and end of the string. If you want them to match line beginnings and endings you have to specify the /m option. It’s also worth knowing about the \G anchor which only matches at the point where the previous match ended – it is only useful when used with the NextMatch method but then it makes all matches contiguous.
Quantify
Of course we now have the problem that it isn’t unreasonable for an ISBN to be written as ISBN: 9 or ISBN:9 with perhaps even more than one space after the colon. We clearly need a way to specify the number of repeats that are allowed in a matching string. To do this we make use of “quantifiers” following the specification to be repeated. The most commonly used quantifiers are: c7d4d050f977dcfbf7f1585efd211660 In many ways this is the point at which regular expression use starts to become interesting and inevitably more complicated. Things are easy with simple examples not hard to find. For example:@"ISBN:\s*\d"…matches “ISBN:” followed by any number of white-space characters including none at all followed by a digit. Similarly:
@"ISBN:?\s*\d"…matches “ISBN” followed by an optional colon, any number of white-space characters including none followed by a digit.
Quantifiers are easy but there is a subtlety that often goes unnoticed. Quantifiers, by default, are “greedy”. That is they match as many entities as they can even when you might think that the regular expression provides a better match a little further on. The only way to really follow this is by the simplest example. Suppose you need a regular expression to parse some HTML tags:
<div>hello</div>If you want to match just a pair of opening and closing tags you might well try the following regular expression:
Regex ex2= new Regex(@"<div>.*</div>");…which seems to say “the string starts with <div> then any number including zero of other characters followed by </div>”. If you try this out on the example given above you will find that it matches:
MessageBox.Show( ex2.Match(@"<div>hello</div>"). ToString());However if you now try it out against the string:
<div>hello</div><div>world</div>…as in:
MessageBox.Show( ex2.Match( @"<div>hello</div><div>world</div>"). ToString());…you will discover that the match is to the entire string. That is the final </div> in the regular expression is matched to the final </div> in the string even though there is an earlier occurrence of the same substring. This is because the quantifiers are greedy by default and attempt to find the longest possible match. In this case the .* matches everything including the first </div>. So why doesn’t it also match the final </div>? The reason is that if it did the entire regular expression would fail to match anything because there would be no closing </div>. What happens is that the quantifiers continue to match until the regular expression fails, then the regular expression engine backtracks in an effort to find a match.
Notice that all of the standard quantifiers are greedy and will match more than you might expect based on what follows in the regular expression. If you don’t want greedy quantifiers the solution is to use “lazy” quantifiers which are formed by following the standard quantifiers by a question mark. To see this in action, change the previous regular expression to read:
Regex ex2= new Regex(@"<div>.*?</div>");With this change in place the result of matching to:
@"<div>hello</div><div>world</div>")…is just the first pair of <div> brackets – that is <div>hello</div>. Notice that all of the quantifiers, including ?, have a lazy version and yes you can write ?? to mean a lazy “zero or one” occurrence.
The distinction between greedy and lazy quantifiers is perhaps the biggest reason for a reasonably well-tested regular expression to go wrong when used against a wider range of example strings. Always remember that a standard greedy quantifier will match as many times as possible while still allowing the regular expression to match, and its lazy version will match as few as possible times to make the regular expression match.
Grouping and alternatives
Regular strings often have alternative forms. For example the ISBN designator could be simply ISBN: or it could be ISBN-13: or any of many other reasonable variations. You can specify an either/or situation using the vertical bar |, the alternation operator as in x|y which will match an x or a y. For example:@"ISBN:|ISBN-13:"…matches either ISBN: or ISBN-13:. This is easy enough but what about:
@"ISBN:|ISBN-13:\s*\d"At first glance this seems to match either ISBN: or ISBN-13 followed by any number of white space characters and a single digit – but it doesn’t. The | operator has the lowest priority and the alternative matches are everything the left and everything to the right, i.e. either ISBN: or ISBN-13:\s*\d. To match the white space and digit in both forms of the ISBN suffix we would have to write:
@"ISBN:\s*\d|ISBN-13:\s*\d"Clearly having to repeat everything that is in common on either side of the alternation operator is going to make things difficult and this is where grouping comes in. Anything grouped between parentheses is treated as a single unit – and grouping has a higher priority than the alternation operator. So for example:
@"(ISBN:|ISBN-13:)\s*\d"…matches either form of the ISBN suffix followed by any number of white space characters and a single digit because the brackets limit the range of the alternation operator to the substrings to the left and right within the bracket.
The greedy/lazy situation also applies to the alternation operator. For example, suppose you try to match the previous un-grouped expression but without the colon:
@"ISBN|ISBN-13"In this case the first pattern, i.e. “ISBN”, will match even if the string is “ISBN-13”. It doesn’t matter that the second expression is a “better” match. No amount of grouping will help with this problem because the shorter match will be tried and succeed first. In this case the solution is to either swap the order of the sub-expressions so that the longer comes first or include something that always marks the end of the target string. For example, in this case if we add the colon then the:
ISBN:
…subexpression cannot possibly match the ISBN-13: string.
Capture and backreference
Now that we have explored grouping it is time to introduce the most sophisticated and useful aspect of regular expressions – the idea of “capture”. You may think that brackets are just about grouping together items that should be matched as a group, but there is more. A subexpression, i.e. something between brackets, is said to be “captured” if it matches and captured expressions are remembered by the engine during the match. Notice that a capture can occur before the entire expression has finished matching – indeed a capture can occur even if the entire expression eventually fails to match at all.The .NET regular expression classes make captures available via the capture property and the CaptureCollection. Each capture group, i.e. each sub-expression surrounded by brackets, can be associated with one or more captured string. To be clear, the expression:
@"(<div>)(</div>)"…has two capture groups which by default are numbered from left-to-right with capture group 1 being the (<div>) and capture group 2 being the (</div>). The entire expression can be regarded as capture group 0 as its results are returned first by the .NET framework. If we try out this expression on a suitable string and get the GroupCollection result of the match using the Groups property:
GroupCollection Grps = ex2.Match( @"<div></div><div></div><div></div>") .Groups;Then, in this case, we have three capture groups – the entire expression returned as Grps[0], the first bracket i.e. capture group 1 is returned as Grps[1] and the final bracket i.e. capture group 2 as Grps[2]. The first group, i.e. the entire expression, is reported as matching only once at the start of the test string – after all we only asked for the first match. Getting the first capture group and displaying its one and only capture demonstrates this:
CaptureCollection Caps = Groups[0].Captures; MessageBox.Show( Caps[0].Index.ToString()+ " "+Caps[0].Length.ToString()+ " "+Caps[0].ToString());…which displays 0 11 <div></div> corresponding to the first match of the complete expression. The second capture group was similarly only captured once at the first <div> and:
CaptureCollection Caps = Groups[1].Captures; MessageBox.Show( Caps[0].Index.ToString()+ " "+Caps[0].Length.ToString()+ " "+Caps[0].ToString());…displays 0 5 <div> to indicate that it was captured by the first <div> in the string. The final capture group was also only captured once by the final </div> and:
CaptureCollection Caps = Groups[2].Captures; MessageBox.Show( Caps[0].Index.ToString()+ " "+Caps[0].Length.ToString()+ " "+Caps[0].ToString());…displays 5 6 </div>. Now consider the same argument over again but this time with the expression:
Regex ex2 = new Regex(@"((<div>)(</div>))*");In this case there are four capture groups including the entire expression. Capture group 0 is the expression ((<div>)(</div>))* and this is captured once starting at 0 matching the entire string of three repeats, i.e. length 33. The next capture group is the first, i.e. outer, bracket ((<div>)(</div>)) and it is captured three times, corresponding to the three repeats. If you try:
CaptureCollection Caps = Groups[1].Captures; for (int i = 0; i <= Caps.Count - 1; i++) { MessageBox.Show( Caps[i].Index.ToString() + " " + Caps[i].Length.ToString() + " " + Caps[i].ToString()); }
…you will find the captures are at 0, 11 and 22. The two remaining captures correspond to the <div> at 0, 11 and 22 and the </div> at 5, 16 and 27. Notice that a capture is stored each time the bracket contents match.
Back referencences
So far so good but what can you use captures for? The answer is two-fold – more sophisticated regular expressions and replacements. Let’s start with their use in building more sophisticated regular expressions. Using the default numbering system described above you can refer to a previous capture in the regular expression. That is, if you write \n where n is the number of a capture group the expression will specify that value of the capture group – confused? It’s easy once you have seen it in action. Consider the task of checking that html tags occur in the correct opening and closing pairs. That is, if you find a <div> tag the next closing tag to the right should be a <\div>. You can already write a regular expression to detect this condition but captures and back references make it much easier. If you start the regular expression with a sub expression that captures the string within the brackets then you can check that the same word occurs within the closing bracket using a back reference to the capture group:
Regex ex2= new Regex(@"<(div)></\1>");Notice the \1 in the final part of the expression tells the regular expression engine to retrieve the last match of the first capture group. If you try this out you will find that it matches <div><\div> but not <div><\pr>, say. You could have done the same thing without using a back reference but it’s easy to extend the expression to cope with additional tags. For example :
Regex ex2= new Regex( @"<(div|pr|span|script)></\1>");…matches correctly closed div, pr, span and script tags.
If you are still not convinced of the power of capture and back reference try and write a regular expression that detects repeated words without using them. The solution using a back reference is almost trivial:
Regex ex2= new Regex(@"\b(\w+)\s+\1\b");The first part of the expression simply matches a word by the following process – start at word boundary capture as many word characters as you can, then allow one or more white space characters. Finally check to see if the next word is the same as the capture. The only tricky bit is remembering to put the word boundary at the end. Without it you will match words that repeat as a suffix as in “the theory”.
As well as anonymous captures you can also create named captures using:
(?<name>regex)…or:
(?'name'regex)You can then refer the capture by name using the syntax:
\<name>…or:
\'name'Using a named capture our previous duplicate word regular expression can be written as:
@"\b(?<word>\w+)\s+\<word>\b"If you need to process named captures outside of a regular expression, i.e. using the Capture classes, then you still have to use capture numbers and you need to know that named captures are numbered left to right and outer to inner after all the unnamed captures have been numbered.
If you need to group items together but don’t want to make use of a capture you can use:
(?:regex)
This works exactly as it would without the ?: but the bracket is left out of the list of capture groups. This can improve the efficiency of a regular expression but this usually isn’t an issue.
Advanced capture
There other capture group constructs but these are far less useful and, because they are even more subtle, have a reputation for introducing bugs. The balancing group is, however, worth knowing about as it gives you the power to balance brackets and other constructs but first we need to know about a few of the other less common groupings – the assertions. There are four of these and the final three are fairly obvious variations on the first. They all serve to impose a condition on the match without affecting what is captured:Zero-width positive lookahead assertion
(?=regex)This continues the match only if the regex matches on the immediate right of the current position but doesn’t capture the regex or backtrack if it fails. For example:
\w+(?=\d)…only matches a word ending in a digit but the digit is not included in the match. That is it matches Paris9 but returns Paris as capture 0. In other words you can use it to assert a pattern that must follow a matched subexpression.
Zero-width negative lookahead assertion
(?!regex)This works like the positive lookahead assertion but the regex has to fail to match on the immediate right. For example:
\w+(?!\d)…only matches a word that doesn’t have a trailing digit.
Zero-width positive lookbehind assertion
(?<=regex)Again this works like the positive lookahead assertion but it the regex has to match on the immediate left. For example:
(?<=\d)\w+…only matches a word that has a leading digit.
Zero-width negative lookbehind assertion
(?<!regex)This is just the negation of the Zero-width positive lookbehind assertion. For example:
(?<!\d)\w+…only matches a word that doesn’t have a leading digit.
Now that we have seen the assertions we can move on to consider the balancing group:
(?<name1-name2>regex)This works by deleting the current capture from the capture collection for name2 and storing everything since the last capture in the capture collection for name1. If there is no current capture for name2 then backtracking occurs and if this doesn’t succeed the expression fails. In many cases all you are doing is trying to reduce the capture count for name2 and in this case you can leave out any reference to name1.
This sounds complicated but in practice it isn’t too difficult. For example, let’s write an expression that matches any number of As followed by the same number of Bs:
Regex ex3 = new Regex( @"^(?<COUNT>A)+(?<-COUNT>B)+");This works, up to a point, in that it matches equal number of A and Bs starting from the beginning of the string but it doesn’t reject a string like AABBB which it simply matches to AABB. Each time the first capture group hits an A it adds a capture to the capture set – so in this case there are two captures when the second capture group hits the first B. This reduces A’s capture set to 1 and then to zero when the second B is encountered which causes the match to backtrack to the second B when the third B is encountered and the match succeeds. To make the entire match fail we also have to include the condition that we should now be at the end of the string.
Regex ex3 = new Regex( @"^(?<COUNT>A)+(?<-COUNT>B)+$");This now fails on AABBB but it matches AAABB because in the case the second capture group doesn’t fail before we reach the end of the string. We really need a test that amounts to “at the end of the string/match the count capture group should be null”.
To do this we need some sort of conditional test on the capture and .NET provides just this:
(?(name)regex1|regex2)…will use regex1 if the capture is non-empty and regex2 if it is empty. In fact this conditional is more general than this in that name can be a general regular expression. You can leave regex2 out if you want an “if then” rather than an “if then else”.
With this our new expression is:
Regex ex3 = new Regex( @"^(?<COUNT>A)+(?<-COUNT>B)+ (?(COUNT)^.)$");The ^. is doesn’t match any character and so it forces the match to fail if the capture group isn’t empty. A more symmetrical if…then…else form of the same expression is:
Regex ex3 = new Regex( @"^(?<COUNT>A)+(?<-COUNT>B)+ (?(COUNT)^.|(?=$))");In this case the else part of the conditional asserts that we are at the end of the string.
Replacements
So far we have created regular expressions with the idea that we can use them to test that a string meets a specification or to extract a substring. These are the two conventional uses of regular expressions. However you can also use them to perform some very complicated string editing and rearrangements. The whole key to this idea is the notion that you can use the captures as part of the specified replacement string. The only hitch is that the substitution strings use a slightly different syntax to a regular expression.The Replace method:
ex1.Replace(input,substitution)…simply takes every match of the associated regular expression and performs the substitution specified. Notice that it performs the substitution on every match and the result returned is the entire string with the substitutions made. There are other versions of the Replace method but they all work in more or less the same way. For example, if we define the regular expression:
Regex ex1 = new Regex(@"(ISBN|ISBN-13)");…and apply the following replacement:
MessageBox.Show( ex1.Replace(@"ISBN: 978-1871962406", "ISBN-13"));…then the ISBN suffix will be replaced by ISBN-13. Notice that an ISBN-13 suffix will also be replaced by ISBN-13 so making all ISBN strings consistent. Also notice that if there are multiple ISBNs within the string they will all be matched and replaced. There are versions of the method that allow you to restrict the number of matches that are replaced.
This is easy enough to follow and works well as long as you have defined your regular expression precisely enough. More sophisticated is the use of capture groups within the substitution string. You can use:
@"$n"…to refer to capture group n or:
@"${name}"…to refer to a capture group by name. There are a range of other substitution strings but these are fairly obvious in use.
As an example of how this all works consider the problem of converting a US format date to a UK format date. First we need a regular expression to match the mm/dd/yyyy format:
Regex ex1 = new Regex( @"(?<month>\d{1,2})/ (?<day>\d{1,2})/ (?<year>\d{4})");
This isn’t a particularly sophisticated regular expression but we have allowed one or two digits for the month and day numbers but insisted on four for the year number. You can write a more interesting and flexible regular expression for use with real data. Notice that we have three named capture groups corresponding to month, day and year. To create a European style date all we have to do assemble the capture groups in the correct order in a substitution string:
MessageBox.Show( ex1.Replace(@" 10/2/2008", "${day}/${month}/${year}$"));
Sets the state of an opportunity to Lost
Sets the state of an opportunity to Lost.
//# The following code example shows how to use the LoseOpportunity message. // Set up the CRM service. CrmAuthenticationToken token = new CrmAuthenticationToken(); // You can use enums.cs from the SDK\Helpers folder to get the enumeration for Active Directory authentication. token.AuthenticationType = 0; token.OrganizationName = "AdventureWorksCycle"; CrmService service = new CrmService(); service.Url = "http://: /mscrmservices/2007/crmservice.asmx"; service.CrmAuthenticationTokenValue = token; service.Credentials = System.Net.CredentialCache.DefaultCredentials; //Set up the data required for this sample. // Create an account for the opportunity's potential customer. account potentialCustomer = new account(); potentialCustomer.name = "Adventure Works Cycle"; Guid createdAccountId = service.Create(potentialCustomer); // Build a query for US Dollar currency. QueryByAttribute dollarQuery = new QueryByAttribute(); dollarQuery.EntityName = EntityName.transactioncurrency.ToString(); dollarQuery.Attributes = new string[] { "currencyname" }; dollarQuery.Values = new string[] { "US Dollar" }; // Be aware that using AllColumns may adversely affect // performance and cause unwanted cascading in subsequent // updates. A best practice is to retrieve the least amount of // data required. dollarQuery.ColumnSet = new AllColumns(); // Create the US currency request. RetrieveMultipleRequest dollarRequest = new RetrieveMultipleRequest(); dollarRequest.Query = dollarQuery; // Get US currency to use in the opportunity. RetrieveMultipleResponse dollarResponse = (RetrieveMultipleResponse)service.Execute(dollarRequest); transactioncurrency usCurrency = (transactioncurrency)dollarResponse.BusinessEntityCollection.BusinessEntities[0]; // Create an opportunity. opportunity loseOpportunity = new opportunity(); loseOpportunity.customerid = new Customer(); loseOpportunity.customerid.type = EntityName.account.ToString(); loseOpportunity.customerid.Value = createdAccountId; loseOpportunity.name = "SDK Sample for LoseOpportunity Message"; loseOpportunity.transactioncurrencyid = new Lookup(); loseOpportunity.transactioncurrencyid.type = EntityName.transactioncurrency.ToString(); loseOpportunity.transactioncurrencyid.Value = usCurrency.transactioncurrencyid.Value; Guid loseOpportunityId = service.Create(loseOpportunity); // Create an opportunityclose object. opportunityclose oppClose = new opportunityclose(); // Set the opportunityclose properties. oppClose.subject = "SDK Sample for LoseOpportunity Message"; // Set the opportunityid to an existing opportunity. oppClose.opportunityid = new Lookup(); oppClose.opportunityid.type = EntityName.opportunity.ToString(); oppClose.opportunityid.Value = loseOpportunityId; // Create the request. LoseOpportunityRequest loseOppReq = new LoseOpportunityRequest(); loseOppReq.OpportunityClose = oppClose; // A status of -1 will have the platform set the status to the appropriate value. loseOppReq.Status = -1; // Execute the request. service.Execute(loseOppReq);
Reflection
Reflection provides objects (of type Type) that encapsulate assemblies, modules and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you are using attributes in your code, Reflection enables you to access them.
Here's a simple example of Reflection using the static method GetType - inherited by all types from the Object base class - to obtain the type of a variable:
// Using GetType to obtain type information:
int i = 42;
System.Type type = i.GetType();
System.Console.WriteLine(type);
In this example, Reflection is used to obtain the full name of a loaded assembly:
// Using Reflection to get information from an Assembly:
System.Reflection.Assembly o = System.Reflection.Assembly.Load("mscorlib.dll");
System.Console.WriteLine(o.GetName());
The output is:
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Check the Follwing video for more information:
ImportCompressedAllXml Message
Import all customizations from an XML file that has been compressed using the WinZip format.
This request requires an ImportExportXml file for import. This example exports this file from CRM and then imports it back into Microsoft Dynamics CRM.
[C#]
// Set up the CRM service.
CrmAuthenticationToken token = new CrmAuthenticationToken();
// You can use enums.cs from the SDK\Helpers folder to get the enumeration for Active Directory authentication.
token.AuthenticationType = 0;
token.OrganizationName = "AdventureWorksCycle";
CrmService service = new CrmService();
service.Url = "http://: /mscrmservices/2007/crmservice.asmx";
service.CrmAuthenticationTokenValue = token;
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Create the request.
ExportCompressedAllXmlRequest requestExport = new ExportCompressedAllXmlRequest();
requestExport.EmbeddedFileName = "customizations.xml";
// Execute the request.
ExportCompressedAllXmlResponse responseExport = (ExportCompressedAllXmlResponse)service.Execute(requestExport);
// Get the compressed data
byte[] compressedXML = responseExport.ExportCompressedXml;
// Create the request.
ImportCompressedAllXmlRequest request = new ImportCompressedAllXmlRequest();
// Assign the compressed data
request.CompressedCustomizationXml = compressedXML;
// Execute the request.
ImportCompressedAllXmlResponse response = (ImportCompressedAllXmlResponse)service.Execute(request);
ImportAllXml Message
Import all customizations from an XML file.
//# This request requires an ImportExportXml file for import. This example exports this file from CRM and then imports it back into Microsoft Dynamics CRM.
// Set up the CRM service.
CrmAuthenticationToken token = new CrmAuthenticationToken();
// You can use enums.cs from the SDK\Helpers folder to get the enumeration for Active Directory authentication.
token.AuthenticationType = 0;
token.OrganizationName = "AdventureWorksCycle";
CrmService service = new CrmService();
service.Url = "http://: /mscrmservices/2007/crmservice.asmx";
service.CrmAuthenticationTokenValue = token;
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
// This is a potentially long running operation. The default 90-second
// time-out might be too short. Set the time-out to be 5 minutes.
// This property takes milliseconds.
service.Timeout = 300 * 1000;
// Create the request.
ExportAllXmlRequest request = new ExportAllXmlRequest();
// Execute the request.
ExportAllXmlResponse exportResponse = (ExportAllXmlResponse)service.Execute((Request)request);
// Create the request.
ImportAllXmlRequest importRequest = new ImportAllXmlRequest();
// Tell the request where the temporary XML file is located.
importRequest.CustomizationXml = exportResponse.ExportXml;
// Execute the import.
ImportAllXmlResponse importResponse = (ImportAllXmlResponse)service.Execute(importRequest);
Understanding Hierarchical Entity Relationships
Hierarchical entity relationships require that one of the records have a field to store a unique identifier that references another record. The record that stores the reference to another record is called the child record ( A record in a hierarchical relationship with a parent record where a reference to the parent record is stored in the record. One parent record can be related to many child records. Child records have lookup fields in the form to allow them to be related to a parent record. ) . The record referenced by the unique identifier in the child record is called the parent record ( A record that is in a hierarchical relationship with a child record, where a reference to the record is stored in the child record. One parent record can be related to many child records. ) .
A hierarchical relationship allows each child record ( A record in a hierarchical relationship with a parent record where a reference to the parent record is stored in the record. One parent record can be related to many child records. Child records have lookup fields in the form to allow them to be related to a parent record. ) to store a reference to one parent record ( A record that is in a hierarchical relationship with a child record, where a reference to the record is stored in the child record. One parent record can be related to many child records. ) . A parent record can be referenced by an unlimited number of child records. The parent record can display all the child records in an associated view ( The view of an entity that is displayed in the forms of other entities. The associated view is different from the views that are visible for the entity in its own area of the user interface. For example, in an account record, under Details, you can click Contacts to view and open a contact form. That is the Contacts associated view. There can be only one associated view of each entity. ) .
Issues related to Hierarchical relationships include:
· Defining Relationships
· Data Integrity
· Relationship Behavior
· Limitations for Hierarchical Relationships
· Mapping
Relationships are defined between entities. The entity that will represent the child records is called the related entity ( An entity that is associated with a primary entity (record type) through a unique reference defined by using a lookup control on the related entity form. For example, an account has a unique reference to a primary contact. ) . A relationship attribute ( An attribute that exists in a related entity when a hierarchical relationship exists. When added to the form of the related entity, a lookup control is displayed to allow the record to be related to another record as defined in the relationship. ) , also known as a lookup attribute ( An attribute used to create a reference to a related record. Also known as a relationship attribute. ) , is created on the related entity to allow records to store a reference to a parent record. The entity that will represent the parent records is called the primary entity ( The entity that a related entity is associated to. Sometimes called a parent entity. ) in the relationship.
When you create or edit a relationship between entities in Microsoft Dynamics CRM you must start from one of the entities. Which entity is not important because only one relationship will be created and only one relationship needs to be edited. The terminology used depends on whether you start from the primary entity ( The entity that a related entity is associated to. Sometimes called a parent entity. ) or the related entity ( An entity that is associated with a primary entity (record type) through a unique reference defined by using a lookup control on the related entity form. For example, an account has a unique reference to a primary contact. ) .
o A 1:N Relationship is a hierarchical relationship created or viewed from the primary entity. Any one record from the primary entity can be referenced by many records from the related entity.
o A N:1 Relationship is a hierarchical relationship created or viewed from the related entity. Many records from the related entity can reference any one record from the primary entity.
Note: It is important to remember that the same relationship can be viewed from either of the two entities that participate in the relationship.
Data Integrity
A hierarchical relationship introduces the opportunity to define rules for data integrity. For example, an opportunity ( A potential revenue-generating event or sale to an account that needs to be tracked through a sales process to completion. ) record has no meaning if it isn't associated with a customer record. Microsoft Dynamics CRM requires that an opportunity record be related to a customer record. However, a task activity ( An action to be performed, such as a task, or a communication item that is sent or received, for example, e-mail, phone calls, and appointments. The status of activities is tracked and the activity history is stored in the system, so users can view the open and closed activities. ) can be meaningful whether it is associated to another record or not. Relating a task activity to another record is optional.
When you create a relationship, you must choose whether to enforce rules for data integrity. If you make the relationship attribute on the related entity a required field by setting a requirement level ( A setting that determines whether users must enter data. For example, when the requirement level of a field is set to Business Required, users will be unable to save the record without entering data in that field. The field will also appear in the Quick Create form. ) of Business Required, you can guarantee that each of the related entity records created through the Microsoft Dynamics CRM application will be related to a record of the parent entity.
Note: Field level constraints only apply to the Microsoft Dynamics CRM application. Records created programmatically through the Microsoft Dynamics CRM Web services are not required to respect field level constraints.
Relationship Behavior
Once you create a hierarchical relationship you can control how the relationship behaves to support both data integrity and business rules for your organization. The relationship can control how actions performed on a parent record will cascade down to child records.
You can configure the relationship behavior for the following actions performed on the record of the primary entity:
· Assign ( The related records will be assigned to the same user. )
· Share ( The related entity records will also be shared with the same user or team. )
· Unshare ( The related entity records will no longer be shared with the same user or team. )
· Reparent ( If the owner of the primary entity record changes because the primary entity record was reparented, the owner of any related records will be set to the same owner as the primary entity record. )
· Delete ( The related records can be deleted, unlinked from the primary entity record, or the delete action can be canceled. )
· Merge ( The related records associated with the subordinate record will be reparented to the master record. )
You can choose from three pre-defined and commonly used types of behavior, or you can choose to configure the appropriate cascading action for each action performed on the record of the primary entity.
The three predefined types of behavior are:
· Parental
In a Parental type of behavior, all actions cascade down to the related records. For example, if a parent record is deleted, all child records will also be deleted. If a parent record is reassigned, all the child records are reassigned to the same user.
· Referential
In a Referential type of behavior, none of the actions will cascade down to child records. For example, when a parent record is deleted, the data linking that record in any child records is removed.
· Referential, Restrict Delete
The Referential, Restrict Delete type of behavior is the same as Referential except that the deletion action is not allowed if there are any related records.
You can also choose to define specific cascading behavior for each of the actions by choosing the Configurable Cascading type of behavior. For most actions, your choices are:
· Cascade All
This is the behavior of the Parental type of behavior. All actions will cascade to all child records, including inactive records.
· Cascade Active
Actions will only cascade down to active child records.
· Cascade User-Owned
Actions will only cascade down to child records assigned to the same user as the owner of the parent record.
· Cascade None
This is the behavior of the Referential type of behavior. No actions will cascade.
Data integrity must be preserved when data in records changes or when the status of records change. For example, deleting a parent record breaks the data integrity of any child records if the relationship is required. There are three ways to address this:
· Use the Referential, Restrict Delete type of behavior to prevent the deletion of any records that have dependent child records.
· Use the Parental type of behavior to delete any dependent child records for any parent records that are deleted.
· Use the Configurable Cascading type of behavior and set the Delete action to either Cascade All or Restrict.
If the relationship is not required, it is sufficient to remove the data that establishes the link to the deleted parent record.
In addition to data integrity, your business may have rules that should be applied when data in records changes or when the status of records changes. For example, some organizations may want to reassign all child records when the a parent record is reassigned. The Relationship behavior can cascade this action so it does not need to be done manually.
Limitations for Hierarchical Relationships
· Parental Relationships
Each entity can participate in only one parental ( A relationship between entities in which any action taken on a record of the parent entity is also taken on any child entity records that are related to the parent entity record. For example, if you delete a record in the parent entity, the related child entity records are also deleted; or if you share a parent entity record, the related records from the child entity are also shared. ) relationship. Most Microsoft Dynamics CRM system entities ( Entities that are included in Microsoft Dynamics CRM by default, such as Account. ) already participate in a parental relationship and this relationship cannot be changed.
· Number of Relationships
Enities can have referential relationships with any entity, including system entities. You can create multiple relationships between two entities. Entities can even have referential relationships with themselves - allowing linked records of the same type. However, a record cannot be linked to itself.
· Relationships with Customer Records
Customers in Microsoft Dynamics CRM may be Accounts or Contacts. These two entities together represent a composite Customer ( The account or contact with which a business unit conducts a business transaction. ) entity. Some Microsoft Dynamics CRM system entities, such as Opportunity and Case must be related to a Customer. However, you cannot create this type of relationship with custom entities.
Mapping
New child records can be created by users in the associated view ( The view of an entity that is displayed in the forms of other entities. The associated view is different from the views that are visible for the entity in its own area of the user interface. For example, in an account record, under Details, you can click Contacts to view and open a contact form. That is the Contacts associated view. There can be only one associated view of each entity. ) if they click the New button. When this happens, data from the parent record is copied into the form for the new child record. By default, a reference to the parent record is always copied to the relationship lookup field in the child record. You can choose whether data from other fields should be copied at the same time.
Clone Message
Copies an existing contract and its line items.
//# The following code example demonstrates how to clone a contract.
// Set up the CRM Service.
CrmAuthenticationToken token = new CrmAuthenticationToken();
// You can use enums.cs from the SDK\Helpers folder to get the enumeration for Active Directory authentication.
token.AuthenticationType = 0;
token.OrganizationName = "AdventureWorksCycle";
CrmService service = new CrmService();
service.Url = "http://: /mscrmservices/2007/crmservice.asmx";
service.CrmAuthenticationTokenValue = token;
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Create the request object.
CloneContractRequest clone = new CloneContractRequest();
// Set the properties of the request object.
clone.ContractId = new Guid("C15AF217-C17E-DA11-B90F-000874DE7397");
clone.IncludeCanceledLines = false;
clone.ReturnDynamicEntities = false;
// Execute the request.
CloneContractResponse cloned = (CloneContractResponse) service.Execute(clone);