The best place for someone starting with development in Microsoft Dynamics CRM 4.0 and MOSS development.
Bye…
The best place for someone starting with development in Microsoft Dynamics CRM 4.0 and MOSS development.
Bye…
In CRM 3.0, following were the events against which we could have written our callouts
Pre/Post – Create, Update, Delete, Assign, SetState, Merge.
PreSend, PostDeliver.
In CRM 4.0, the above event are now referred as messages for plug-ins. All the above events that were in CRM 3.0 are there as well as there many new messages/events have been added against which plug-ins can be attached.
For e.g. we can attach a plug-in against AddMembers message for team entity which would fire when we are adding members to a team.or attach a plug-in against Retrieve message for say lead entity which would fire when retrieve method of CrmService is used.
We can find all the new messages and the entities on which they work in SDK.
When we add a web reference to a web service behind the screen wsdl.exe is run which creates the proxy class. Proxy class contains both synchronous and asynchronous flavors of each web method.For simple HelloWorld() web method following methods are there in the proxy class
Public string HelloWorld()
Public string HelloWorldAsync();
Public string HelloWorldAsync(object userState);
We call the HelloWorldAsync() method which in turn calls the following method of the proxy class InvokeAsync()
// Summary:
// Invokes the specified method asynchronously.
// Parameters:
// methodName:
// The name of the method to invoke.
// parameters:
// The parameters to pass to the method.
// callback:
// The delegate called when the method invocation has completed.
protected void InvokeAsync(string methodName, object[] parameters, SendOrPostCallback callback);
HelloWorldCompletedEventArgs– This class is also created by wsdl.exe which contains the result of our operation.
Suppose this is our simple web service, we have introduced delay to understand the asynchronous behavior.
[WebMethod]
public string HelloWorld() {
Thread.Sleep(5000);
return “Hello World”;
}
Now to call the above webservice method asynchrously in a windows application client we need to do the following
Say we have want to call the HelloWorld method asynchronously on the click of the button,
private void btnCallService_Click(object sender, EventArgs e)
{
// Create the instance of the proxy class
Service myService = new Service();
// Register an eventhandler for HelloWorldCompleted event
// The eventhandler would be called when the request is
// completed
myService.HelloWorldCompleted += new
HelloWorldCompletedEventHandler(this.HelloWorldCompleted);
// instead of calling the synchronous HelloWorld() we need
// to call the HelloWorldAsync() method
myService.HelloWorldAsync();
}
void HelloWorldCompleted(object sender,HelloWorldCompletedEventArgs args){
// Display the reutrn value
MessageBox.Show(args.Result);
}
To call the above web method in an asp.net client we need to add the following attribute in the @Page directive
Async=”true”
Bye..
There is a method named ExecuteWorkflowRequest using which we can execute our workflow programmatically. We had a requirement to find all the opportunities which haven’t been modified for past 30 days and to decrease their probability attribute value by 10.
Now the thing over here was that there wasn’t any specific event against which we could have fired the above workflow. So we thought of writing an application which than we could scheduled, which will periodically run the above workflow
This is how we implemeneted it within a windows application
private void Form1_Load(object sender, EventArgs e){
CrmAuthenticationToken token = new CrmAuthenticationToken();
token.OrganizationName = “organizationName”;
//0 – AD
//1 – Passport
//2 – Form Authentication
token.AuthenticationType = 0;
CrmService crmService = new CrmService();
crmService.Credentials = System.Net.CredentialCache.DefaultCredentials;
crmService.CrmAuthenticationTokenValue = token;
crmService.Url = “http://servername:port/mscrmservices/2007/crmservice.asmx”;
try{
// Create an ExecuteWorkflow request.
ExecuteWorkflowRequest request = new ExecuteWorkflowRequest();
//Assign the ID of the workflow you want to execute to the request.
// use this query to get the id select parentworkflowid,name,* from dbo.Workflow
// id is the parentworkflowid
request.WorkflowId = new Guid(“21B9528D-D13D-4B93-9F91-FA7468D3C82C”);
// We want to run it against all the opportunity which are in open state
ArrayList OpportunityGuids = GetOpportunityGuids(crmService);
foreach (String oppGuid in OpportunityGuids){
//Assign the ID of the entity to execute the workflow on to the request.
request.EntityId = new Guid(oppGuid);
ExecuteWorkflowResponse response = (ExecuteWorkflowResponse)crmService.Execute(request);}
// Execute the workflow. }
catch (SoapException ex){
// write in log}
catch (Exception ex){
// write in log} }
private ArrayList GetOpportunityGuids(CrmService crmService){
// using QueryByAttribute to retrieve all the opportunity having statuscode as 1 i.e. Open
QueryByAttribute myOppQuery = new QueryByAttribute();
myOppQuery.Attributes = new String[] { “statuscode” };
myOppQuery.Values = new String[] {“1”};
ColumnSet myCols = new ColumnSet();
myOppQuery.ColumnSet = myCols;
myOppQuery.EntityName = EntityName.opportunity.ToString();
WindowsFormsApplication2.CrmSdk.BusinessEntityCollection myOppCollection= crmService.RetrieveMultiple(myOppQuery);
ArrayList opportunityGuids = new ArrayList();
foreach (WindowsFormsApplication2.CrmSdk.BusinessEntity opp in myOppCollection.BusinessEntities ){
opportunity myOpp = (opportunity)opp;
opportunityGuids.Add(myOpp.opportunityid.Value.ToString()); }
return opportunityGuids;
}
Bye ..
To use CrmService or Metadata Service (CRM 4.0) within an ASP.NET page or a windows application we need to make use of CRM Authentication token.If we are using Active Directory Authentication this is the code for that
CrmAuthenticationToken token = new CrmAuthenticationToken();
token.OrganizationName = “organizationName”;
//0 – AD
//1 – Passport
//2 – Form Authentication
token.AuthenticationType = 0;
CrmService service = new CrmService();
service.Credentials =System.Net.CredentialCache.DefaultCredentials;
service.CrmAuthenticationTokenValue = token;
service.Url = “http://servername:port/mscrmservices/2007/crmservice.asmx”;
try{
WhoAmIRequest myReq = new CrmSdk.WhoAmIRequest();
WhoAmIResponse myResp = (CrmSdk.WhoAmIResponse)service.Execute(myReq);
}
catch (SoapException ex){
Response.Write(ex.Detail.InnerText);
}
catch (Exception ex){
Response.Write(ex.Message);}
If we get the above unauthorized access error it could be because either there is problem in our CrmAuthenticationToken, may be we could have assigned wrong organization name or authentication type. If we are using CrmService in an ASP.NET page than we need to use impersonation.
<authentication mode=“Windows“/>
<identity impersonate=“true“/>
If we are using 2006 end point of CrmService we don’t have to use CrmAuthenticationToken.
By default, ASP.NET permits only files that are 4,096 kilobytes (KB) or less to be uploaded to the Web server. To upload larger files, we must change the maxRequestLength parameter of the <httpRuntime> section in the Web.config file. By default, the <httpRuntime> element is set to the following parameters in the Machine.config file:
<httpRuntime
executionTimeout=“90“
maxRequestLength=“4096“
useFullyQualifiedRedirectUrl=“false“
minFreeThreads=“8“
minLocalRequestFreeThreads=“4“
appRequestQueueLimit=“100“
/>
We can change the value of maxRequestLength to a desired value in our web.config of the application. For 10 mb we can set it to 10240 KB. Even in this case if user tries to upload a file with size more than 10 mb we than get the above “Page cannot be displayed error ” or the page simply hang up. In this case we can catch the error in the Application_Error event handler of the Global.asax file.
void Application_Error(object sender, EventArgs e)
{
if (System.IO.Path.GetFileName(Request.Path) == “Default.aspx”)
{
System.Exception appException = Server.GetLastError();
if (appException.InnerException.Message == “Maximum request length exceeded.”)
{
Server.ClearError();
Response.Write(“The form submission cannot be processed because it exceeded the maximum length allowed by the Web administrator. Please resubmit the form with less data.”);
Response.Write(“<BR><a href=’Default.aspx’>Click Here to go back to page</a> </BR>”);
Response.End(); } } }
I tried with the above code, but it isn’t consistent.
The best solution for this could be to set the value of maxRequestLength to a very high value.
and checking in the code for the size.
Say changing the value to say 700mb ( not sure what the maximum length of request could be)
<httpRuntime useFullyQualifiedRedirectUrl=“true“
maxRequestLength=“716800“
/>
And checking for the length in your code
// Putting the constraint of 1 mb
if (FileUpload1.FileContent.Length < 1024){
FileUpload1.SaveAs(@”C:/MyFolder/” + FileUpload1.FileName);}
else{
return;}
At least the above solution would save us from the page not displayed error.
And the last solution which i found was creating an httpmodule to intercept the web request.
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace HAMModule{
public class MyModule : IHttpModule{
public void Init(HttpApplication app){
app.BeginRequest += new EventHandler(app_BeginRequest);
}
void app_BeginRequest(object sender, EventArgs e){
HttpContext context = ((HttpApplication)sender).Context;
// check for size if more than 4 mb
if (context.Request.ContentLength > 4096000){
IServiceProvider provider = (IServiceProvider)context;
HttpWorkerRequest wr = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
// Check if body contains data
if (wr.HasEntityBody()){
// get the total body length
int requestLength = wr.GetTotalEntityBodyLength();
// Get the initial bytes loaded
int initialBytes = wr.GetPreloadedEntityBody().Length;
if (!wr.IsEntireEntityBodyIsPreloaded()){
byte[] buffer = new byte[512000];
// Set the received bytes to initial bytes before start reading
int receivedBytes = initialBytes;
while (requestLength – receivedBytes >= initialBytes){
// Read another set of bytes
initialBytes = wr.ReadEntityBody(buffer, buffer.Length);
// Update the received bytes
receivedBytes += initialBytes;
}
initialBytes = wr.ReadEntityBody(buffer, requestLength – receivedBytes);}}
// Redirect the user to an error page.
context.Response.Redirect(“Error.aspx”);}}
public void Dispose(){}
}}
and add the following information to web.config
<httpModules>
<add type=“HAMModule.MyModule“ name=“MyModule“/>
</httpModules>
inside
<system.web>
The last solution worked properly!!!!
BeginRequest event –The BeginRequest event signals the creation of any given new request. This event is always raised and is always the first event to occur during the processing of a request.
Article on creating a custom http module
http://msdn.microsoft.com/en-us/library/ms227673(VS.80).aspx
Bye..