I am creating a custom workflow in Microsoft Dynamics CRM to automatically update a field when a record is saved.
A developer on a forum provided the following source code; but he is not responding to my questions.
public class SalesRepActivity2 : WorkFlowActivityBase
{
[Input("Sales Rep Name")]
public InArgument<string> SalesRepName { get; set; }
[Output("Sales Rep")]
[ReferenceTarget("systemuser")]
public OutArgument<EntityReference> SalesRep { get; set; }
[Output("IsSuccess")]
public OutArgument<bool> IsSuccess { get; set; }
[Output("Message")]
public OutArgument<string> Message { get; set; }
protected override void Execute(
CodeActivityContext activityContext,
IWorkflowContext workflowContext,
IOrganizationService CrmService,
ITracingService trace)
{
try
{
string salesRepName = SalesRepName.Get(activityContext);
if (string.IsNullOrWhiteSpace(salesRepName))
{
IsSuccess.Set(activityContext, false);
Message.Set(activityContext, "Sales Rep Name not provided");
}
var QEsystemuser = new QueryExpression("systemuser");
QEsystemuser.ColumnSet.AddColumns("salesrepname");
QEsystemuser.Criteria.AddCondition("salesrepname", ConditionOperator.Equal, salesRepName);
var results = CrmService.RetrieveMultiple(QEsystemuser);
if (results == null || !results.Entities.Any())
{
IsSuccess.Set(activityContext, false);
Message.Set(activityContext, "User with " + salesRepName + " not found");
return;
}
if (results.Entities.Count > 1)
{
IsSuccess.Set(activityContext, false);
Message.Set(activityContext, "Multiple users found with same name : " + salesRepName);
return;
}
IsSuccess.Set(activityContext, true);
SalesRep.Set(activityContext, results.Entities.Single().ToEntityReference());
}
catch (Exception ex)
{
IsSuccess.Set(activityContext, false);
Message.Set(activityContext, "An error occurred trying to find user : " + ex.Message);
}
}
I am trying to get the code to compile on my machine.
I installed the following NuGet packages, which resolved most of the errors:
Microsoft.Xrm.Sdk.Workflow.2015
Microsoft.Xrm.Sdk.2015
But my project cannot resolve the WorkFlowActivityBase class.
Is there a reference I should set or a NuGet package I should install to resolve this?
Thank you.
WorkFlowActivityBase is a custom base class that implements the CodeActivity (System.Activities) anyone can write, it's not an official Dynamics class. Yon can find dozen of classes lie that in the web.
Basically, you should use the CodeActivity. here as an example:
https://learn.microsoft.com/en-us/powerapps/developer/common-data-service/workflow/sample-create-custom-workflow-activity
The code you posted is not a good place for you to start because it makes heavy use of proprietary objects. Ziv has provided good information about extending the CodeActivity class but I do not recommend starting there. Instead read about how to develop custom workflow activities, and write a workflow using the base Microsoft classes so that you understand how they work:
https://learn.microsoft.com/en-us/powerapps/developer/common-data-service/workflow/workflow-extensions
Once you have some experience with creating custom workflows, and you understand the limitations of the base objects, then go back and implement something more fancy.
Here in an exaple from the documentation:
namespace Microsoft.Crm.Sdk.Samples
{
public sealed class SimpleSdkActivity : CodeActivity
{
protected override void Execute(CodeActivityContext executionContext)
{
//Create the tracing service
ITracingService tracingService = executionContext.GetExtension<ITracingService>();
//Create the context
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
...
var systemUsers = service.RetrieveMultiple(QEsystemuser)
}
}
}
Related
I am trying to create mobile app using Xamarin and Realm. I am trying to pull data from server and load it into objects extended by RealmObjects.
code to fetch data from server
public async void getCompanyMaster() {
var uri = new Uri(string.Format(URL, string.Empty));
try
{
getConnection();
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
Company company = JsonConvert.DeserializeObject<Company>(content);
Debug.WriteLine("Company List " );
}
}
catch (Exception e)
{
Debug.WriteLine("Error {0}", e.Message);
}
}
realm model company
namespace DesignModel.Model.Master
{
public class Company : RealmObject
{
public string errorMessage { get; set; }
public string status { get; set; }
[JsonProperty(PropertyName = "companyMaster")]
IList<CompanyMaster> companyMaster { get; }
}
}
realm model for company master
namespace DesignModel.Model.Master
{
public class CompanyMaster : RealmObject
{
public string companyAddress { get; set; }
public string companyId { get; set; }
public string companyName { get; set; }
public string companyPhoneNumber { get; set; }
}
}
now the issue is at following line in getCompanyMaster function
Company company = JsonConvert.DeserializeObject<Company>(content);
it raises an exception
Error Error setting value to 'errorMessage' on
'DesignModel.Model.Master.Company'.
if i do not extend my class from RealmObject then it works fine but when i add RealObject it doesn't work.
the above approach does work in android native but do not know why it doesn't work in xamarin.
sample json
{
"errorMessage": "",
"status": "Ok",
"companyMaster": [
{
"companyAddress": "123 Coffee Street\nSuite 300\nRedmond, WA 98052\nUSA",
"companyId": "cec",
"companyName": "Contoso Entertainment Systems",
"companyPhoneNumber": "425-555-0156"
}]
}
complete stack trace
[0:] Error Newtonsoft.Json.JsonSerializationException: Error setting
value to 'errorMessage' on 'DesignModel.Model.Master.Company'. --->
System.PlatformNotSupportedException: The PCL build of Realm is being
linked which probably means you need to use NuGet or otherwise link a
platform-specific Realm.dll to your main application.
Adding a note from documentation found here
https://realm.io/docs/xamarin/latest/
under Getting Started - Prerequisites
Important note for PCL users - this works via the NuGet Bait and Switch
Trick. You
have to install the Realm NuGet package into every PCL that uses Realm
as well as each of your platform-specific projects, e.g.: your final
app for iOS and Android. If you are using shared projects, you only
have to install the NuGet into each platform-specific project.
What is the difference between IOrganizationService and OrganizationServiceProxy in Dynamics CRM?
Is it related to accessing services in Crm context and outside Crm Context?
Simplest answer is IOrganizationService is an interface whereas OrganizationServiceProxy is a class which implements the IOrganizationService interface. This means any properties/methods on IOrganizationService are by default also available via OrganizationServiceProxy.
If running in the context of a plugin or custom workflow activity it will give you access to an IOrganizationService that you can use to interrogate CRM.
If you are writing something external, such as a windows service or standalone application, then you generally use the class OrganizationServiceProxy to set up a connection to the CRM web service. You can obviously assign this to an IOrganizationService later (e.g. dependency injection / for unit testing purposes). Or if you prefer there is no reason why you can continue to use the OrganizationServiceProxy.
The IOrganisationService is used within plugins and custom workflow activities and derived from the execution context.
While the OrganisationServiceProxy is mainly used for code running outside the Dynamics CRM application.
If you're using the sdk assemblies (specifically microsoft.xrm.sdk.dll), then you'll be using an implementation of IOrganizationService, and the call time will be identical. The main purpose of OrganizationServiceProxy is to provide options for establishing a connection to CRM in code that runs outside of CRM .The OrganizationServiceProxy class implements the IOrganizationService and provides an authenticated WCF channel to the organization service
OrganizationService is a higher level class that provides richer client side functionality and actually uses OrganizationServiceProxy inside it.
The Microsoft.Xrm.Client assembly that holds this higher level API cannot be used in Plugins etc but is intended for rich clients and ASP.NET.
It's worth noting that the Microsoft.Xrm.Client assembly has been removed from the CRM2016 SDK. For 2016 projects you might consider using the XRM Toolking assemblies.
See msdn.microsoft.com/.../dn689057.aspx
It has similar functionality that you mention around the connection manager -msdn.microsoft.com/.../mt608573.aspx
OrganizationServiceProxy is implementation of IOrganizationService. It is similar to case as List is implementation of interface IList. If to speak about why on Earth Microsoft provides both interface and implementation besides testing, I can propose one interesting case which happened in my life. I was in need of re-reading information from dynamics crm. In my case OrganizationServiceProxy got expired faster, then information was received from CRM. In order to fix it I've created following facade:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
namespace OrganizationService
{
public delegate IOrganizationService CreateOrganizationServiceFunc(string organizationServiceUrl, string userName, string password, TimeSpan? timeout = null, bool useSSL = false);
public class OrganizationServiceFacade : IOrganizationService
{
private IOrganizationService _serviceInternal { get; set; }
private CreateOrganizationServiceFunc _creator;
Func<IOrganizationService> _orgServiceFactory;
public OrganizationServiceFacade(Func<IOrganizationService> orgServiceFactory)
{
_orgServiceFactory = orgServiceFactory;
CreateService();
}
private void CreateService()
{
_serviceInternal = _orgServiceFactory();
}
public void Associate(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities)
{
try
{
_serviceInternal.Associate(entityName, entityId, relationship, relatedEntities);
}
catch (System.ServiceModel.Security.MessageSecurityException mex)
{
CreateService();
_serviceInternal.Associate(entityName, entityId, relationship, relatedEntities);
}
}
public Guid Create(Entity entity)
{
Guid result;
try
{
result = _serviceInternal.Create(entity);
}
catch (System.ServiceModel.Security.MessageSecurityException mex)
{
CreateService();
result = _serviceInternal.Create(entity);
}
return result;
}
public void Delete(string entityName, Guid id)
{
try
{
_serviceInternal.Delete(entityName, id);
}
catch (System.ServiceModel.Security.MessageSecurityException mex)
{
CreateService();
_serviceInternal.Delete(entityName, id);
}
}
public void Disassociate(string entityName, Guid entityId, Relationship relationship, EntityReferenceCollection relatedEntities)
{
try
{
_serviceInternal.Disassociate(entityName, entityId, relationship, relatedEntities);
}
catch (System.ServiceModel.Security.MessageSecurityException mex)
{
CreateService();
_serviceInternal.Disassociate(entityName, entityId, relationship, relatedEntities);
}
}
public OrganizationResponse Execute(OrganizationRequest request)
{
try
{
return _serviceInternal.Execute(request);
}
catch (System.ServiceModel.Security.MessageSecurityException mex)
{
CreateService();
return _serviceInternal.Execute(request);
}
}
public Entity Retrieve(string entityName, Guid id, ColumnSet columnSet)
{
try
{
return _serviceInternal.Retrieve(entityName, id, columnSet);
}
catch (System.ServiceModel.Security.MessageSecurityException mex)
{
CreateService();
return _serviceInternal.Retrieve(entityName, id, columnSet);
}
}
public EntityCollection RetrieveMultiple(QueryBase query)
{
try
{
return _serviceInternal.RetrieveMultiple(query);
}
catch (System.ServiceModel.Security.MessageSecurityException mex)
{
CreateService();
return _serviceInternal.RetrieveMultiple(query);
}
}
public void Update(Entity entity)
{
try
{
_serviceInternal.Update(entity);
}
catch (System.ServiceModel.Security.MessageSecurityException mex)
{
CreateService();
_serviceInternal.Update(entity);
}
}
}
}
and then I've got simple reconnect mechanism:
Trace.TraceInformation("Creation of CRM connection");
for (var maxTry = 0; maxTry < reconectionTries; maxTry++)
{
try
{
var service = new OrganizationServiceFacade(() =>
XrmServiceCreator.CreateOrganizationService("organizationServiceUrl",
"username",
"userpassword",
DefaultTimeout));
var response = (WhoAmIResponse) service.Execute(new WhoAmIRequest());
if (response.Results.Count == 0)
{
throw new InvalidDataException($"CRM returned no data in response. Number of retries is: {maxTry}, user name: {ConfigSettings.Default.RunAsUser}, Default timeout = {DefaultTimeout}");
}
return service;
}
catch (Exception e)
{
Trace.TraceError("Exception: {0}", e);
}
}
method XrmServiceCreator.CreateOrganizationService returns instance of IOrganizationService, and behind curtains it creates instance of OrganizationServiceProxy
I'm using the new ASP.NET webapi odata (version 4.0.0 last published 27/2/2013 according to Nuget)
Basically I'm doing it as described here: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api
I'm publishing my data transfer objects and the odata atom pub feed is created but I'd like to have some more control over it. Mainly I'd like to be able to do the following:
decide what goes on the title, author and updated elements for the feed
decide whether or not to have the edit links
change what is shown in <category term="X"and in m:type in sub properties that are classes in my application. Currently they expose the c# class names with the full namespace but I don't want to expose this.
Thanks.
The OData media type formatter is more extensible now. Samples follow.
1) decide what goes on the title, author and updated elements for the feed
public class AtomMetadataFeedSerializer : ODataFeedSerializer
{
public AtomMetadataFeedSerializer(IEdmCollectionTypeReference edmType, ODataSerializerProvider serializerProvider)
: base(edmType, serializerProvider)
{
}
public override ODataFeed CreateODataFeed(IEnumerable feedInstance, ODataSerializerContext writeContext)
{
ODataFeed feed = base.CreateODataFeed(feedInstance, writeContext);
feed.Atom().Title = new AtomTextConstruct { Kind = AtomTextConstructKind.Text, Text = "My Awesome Feed" };
return feed;
}
}
public class CustomSerializerProvider : DefaultODataSerializerProvider
{
public override ODataEntrySerializer CreateEdmTypeSerializer(IEdmTypeReference edmType)
{
if (edmType.IsCollection() && edmType.AsCollection().ElementType().IsEntity())
{
// feed serializer
return new AtomMetadataFeedSerializer(edmType.AsCollection(), this);
}
return base.CreateEdmTypeSerializer(edmType);
}
}
And register the custom serializer provider using,
config.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create(new CustomSerializerProvider(), new DefaultODataDeserializerProvider()));
2) customize edit links
public class CustomEntityTypeSerializer : ODataEntityTypeSerializer
{
public CustomEntityTypeSerializer(IEdmEntityTypeReference edmType, ODataSerializerProvider serializerProvider)
: base(edmType, serializerProvider)
{
}
public override ODataEntry CreateEntry(EntityInstanceContext entityInstanceContext, ODataSerializerContext writeContext)
{
ODataEntry entry = base.CreateEntry(entityInstanceContext, writeContext);
if (notProduceEditLinks)
{
entry.EditLink = null;
}
return entry;
}
}
public class CustomSerializerProvider : DefaultODataSerializerProvider
{
public override ODataEntrySerializer CreateEdmTypeSerializer(IEdmTypeReference edmType)
{
if (edmType.IsEntity())
{
// entity type serializer
return new CustomEntityTypeSerializer(edmType.AsEntity(), this);
}
return base.CreateEdmTypeSerializer(edmType);
}
}
and register the custom serializer provider as above.
We still don't support scenario 3 i.e aliasing type names and namespaces.
I'm using a class test that checks login entity that is being done correctly, but an error occurs that does not seem to return the query in the database, but the application developed in ASP.NET MVC 3 Code First query returns data, I would to know what is wrong and what can be done to solve it.
Upon return of the query gives the following message in the variable:
"Enumeration yielded no results"
Test Method:
[TestMethod()]
public void efetuarLoginTest()
{
EntidadeRepository target = new EntidadeRepository();
string cnpj = "12345678";
string senha = "lalado";
Entidade expected = null; // TODO: Initialize to an appropriate value
Entidade actual;
actual = target.efetuarLogin(cnpj, senha);
Assert.AreNotEqual(expected, actual);
}
Method repository of the entity with the task of returning to the login query:
public Entidade efetuarLogin(string cnpj, string senha)
{
var consulta = from usu in bd.Entidades
where usu.cnpj == cnpj && usu.senha == senha
select usu;
if (consulta.Count() > 0)
{
Entidade e = new Entidade();
e.id_entidade = consulta.First().id_entidade;
e.razao_social = consulta.First().razao_social;
e.cnpj = consulta.First().cnpj;
e.senha = consulta.First().senha;
return e;
}
else
{
return null;
}
}
Class persistence database using the Entity Framework 4.1:
internal class BancoDados: DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingEntitySetNameConvention>();
modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();
base.OnModelCreating(modelBuilder);
}
public DbSet<Entidade> Entidades { get; set; }
public DbSet<Estado> Estados { get; set; }
public DbSet<Administrador> Administradores { get; set; }
public DbSet<Leilao> Leiloes { get; set; }
public DbSet<Lance> Lances { get; set; }
}
Thank You.
for us, this kind of an error was generated because of the right connection string not passed to the EF. If you are using NUnit, NUnit doesn't use your app.config or web.config, you would have to create your assembly.dll.config or nunit project.config. Please check NUnit documentation for usage of config files.
You can verify the connection string passed to NUnit, by examining, DbContext.Database and its properties in debug mode/
Checking your config values, should fix your problem.
I would imagine
if (consulta.Count() > 0)
is throwing the error?
You could change it to
if (consulta != null && consulta.Count() > 0)
When I start to installing using installutil it gives me following error, I have set ServiceInstaller and ServiceInstallerProcess,
System.InvalidOperationException: Installation failed due to the absence of a ServiceProcessInstaller. The ServiceProcessInstaller must either be the containing installer, or it must be present in the Installers collection on the same installer as the ServiceInstaller.
Any ideas on how to fix the problem?
I had the same problem with the Installer and found that in the [YourInstallerClassName].Designer.cs at InitializeComponent() method, the dfault generated code is Missing add the ServiceProcessInstaller
//
// [YourInstallerClassName]
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceInstaller1});
Just add your ServiceProcessInstaller in my case its:
//
// ProjectInstaller
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1, //--> Missing
this.serviceInstaller1});
and the Setup project works.
Usually, this means you failed to attribute your installer with RunInstaller(true). Here's an example of one I have handy that works:
namespace OnpointConnect.WindowsService
{
[RunInstaller(true)]
public partial class OnpointConnectServiceInstaller : Installer
{
private ServiceProcessInstaller processInstaller;
private ServiceInstaller serviceInstaller;
public OnpointConnectServiceInstaller()
{
InitializeComponent();
}
public override string HelpText
{
get
{
return
"/name=[service name]\nThe name to give the OnpointConnect Service. " +
"The default is OnpointConnect. Note that each instance of the service should be installed from a unique directory with its own config file and database.";
}
}
public override void Install(IDictionary stateSaver)
{
Initialize();
base.Install(stateSaver);
}
public override void Uninstall(IDictionary stateSaver)
{
Initialize();
base.Uninstall(stateSaver);
}
private void Initialize()
{
processInstaller = new ServiceProcessInstaller();
serviceInstaller = new ServiceInstaller();
processInstaller.Account = ServiceAccount.LocalSystem;
serviceInstaller.StartType = ServiceStartMode.Manual;
string serviceName = "OnpointConnect";
if (Context.Parameters["name"] != null)
{
serviceName = Context.Parameters["name"];
}
Context.LogMessage("The service name = " + serviceName);
serviceInstaller.ServiceName = serviceName;
try
{
//stash the service name in a file for later use in the service
var writer = new StreamWriter("ServiceName.dat");
try
{
writer.WriteLine(serviceName);
}
finally
{
writer.Close();
}
Installers.Add(serviceInstaller);
Installers.Add(processInstaller);
}
catch (Exception err)
{
Context.LogMessage("An error occured while creating configuration information for the service. The error is "
+ err.Message);
}
}
}
}