I have an ASP.NET MVC 3 application that relies on the user of certificates. When I run the application, I receive an error that says:
Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: ID1024: The configuration property value is not valid.
Property name: 'serviceCertificate'
Error: 'ID1001: The certificate does not have an associated private key.
Thumbprint: '[ID]''
Source Error:
Line 278:
Line 279: <microsoft.identityModel>
Line 280: <service>
Line 281: <audienceUris>
Line 282: <!--<environment name="DEV">-->
ID is actually a full-blown thumbprint. What am I doing wrong? How do I fix this? I suspect that my certificate is not setup properly. However, I'm not sure if this is true, or how to even check. Thank you!
I was able to resolve this issue by doing the following Hope this helps.
public static System.Security.Cryptography.X509Certificates.StoreName StoreName
{
get
{
StoreName storeName = StoreName.My;
if (WebConfigurationManager.AppSettings[SigningStoreName] != null)
storeName = (StoreName)Enum.Parse(typeof(StoreName), WebConfigurationManager.AppSettings[SigningStoreName]);
return storeName;
}
}
public static System.Security.Cryptography.X509Certificates.StoreLocation StoreLocation
{
get
{
StoreLocation storeLocation = StoreLocation.CurrentUser;
if (WebConfigurationManager.AppSettings[SigningStoreLocation] != null)
storeLocation = (StoreLocation)Enum.Parse(typeof(StoreLocation), WebConfigurationManager.AppSettings[SigningStoreLocation]);
return storeLocation;
}
}
public static SigningCredentials GetSigningCredentials()
{
X509Certificate2 cert = CertificateUtil.GetCertificate(StoreName, StoreLocation, WebConfigurationManager.AppSettings[Common.SigningSubjectNameOrThumbprint]);
string signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
, digestAlgorithm = "http://www.w3.org/2000/09/xmldsig#sha1";
RSACryptoServiceProvider rsa = cert.PrivateKey as RSACryptoServiceProvider;
if (rsa == null) rsa = RSA.Create() as RSACryptoServiceProvider;
RsaSecurityKey rsaKey = new RsaSecurityKey(rsa);
RsaKeyIdentifierClause rsaClause = new RsaKeyIdentifierClause(rsa);
SecurityKeyIdentifier signingSki = new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[] { rsaClause });
SigningCredentials signingCredentials = new SigningCredentials(rsaKey, signatureAlgorithm, digestAlgorithm, signingSki);
return signingCredentials;
}
public static X509Certificate2 GetCertificate(StoreName name, StoreLocation location, string subjectNameOrThumbprint)
{
X509Store store = new X509Store(name, location);
X509Certificate2Collection certificates = null;
store.Open(OpenFlags.ReadOnly);
try
{
X509Certificate2 result = null;
certificates = store.Certificates;
if (certificates != null && certificates.Count > 0)
{
result = (from X509Certificate2 cert in certificates
where !string.IsNullOrWhiteSpace(cert.Thumbprint)
&& cert.Thumbprint.ToLower().Replace(" ", "") == subjectNameOrThumbprint.ToLower().Replace(" ", "")
select cert
).FirstOrDefault();
if (result == null)
result = (from X509Certificate2 cert in certificates
where cert.SubjectName != null
&& cert.SubjectName.Name.ToLower().Replace(" ", "") == subjectNameOrThumbprint.ToLower().Replace(" ", "")
select cert
).FirstOrDefault();
}
string errMsg = string.Format("{0} - {1} in {2}", name.ToString(), subjectNameOrThumbprint, location.ToString());
if (result == null)
throw new ApplicationException(string.Format("No certificate was found for {0} ", errMsg));
else if (result.Verify() == false)
throw new ApplicationException(string.Format("Unable to verify certificate for {0}", errMsg));
return result;
}
finally
{
store.Close();
}
}
Related
we need to do a custom cert chain validation, got the code from one of the forums
but in the call back certChain.ChainStatus and ChainElementStatus are empty or null.
its not validating anything where chain status is there, its just skipping.
Anybody has any pointers on this issue, are we missing anything
var root = new X509Certificate2(#"c:\root.cer");
var inter = new X509Certificate2(#"inter.cer");
var validCertificates = new[] { root, inter };
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, certChain, policyErrors) =>
{
return ValidateCertificate(httpRequestMessage, cert, certChain, policyErrors, validCertificates);
};
var httpClient = new HttpClient(handler);
private bool ValidateCertificate(HttpRequestMessage httpRequestMessage, X509Certificate2 cert,
X509Chain certChain, SslPolicyErrors policyErrors, X509Certificate2[] validCertificates)
{
if (certChain.ChainStatus.Any(status => status.Status != X509ChainStatusFlags.UntrustedRoot))
return false;
foreach (var element in certChain.ChainElements)
{
foreach (var status in element.ChainElementStatus) ---skipping this step and not getting inside
{
if (status.Status == X509ChainStatusFlags.UntrustedRoot)
{
certificates
if (validCertificates.Any(cert => cert.RawData.SequenceEqual(element.Certificate.RawData)))
continue;
}
return false;
}
}
return true;
}
Those arrays are empty when the element (or overall chain, depending on which one) have no errors.
You're showing a state that is appropriate to a trusted chain.
I am getting a not verified using the TOTP method I have found on the following link.
OTP code generation and validation with otp.net
!My! code is below.
The _2FAValue line at the top is embedded into the QR barcode that Microsoft Authenticator attaches too.
The _Check... Function is the server ajax call to the server which implements OTP.Net library exposing TOTP calculation.
MakeTOTPSecret creates an SHA1 version of a Guid which is applied to the User profile and stored in _gTOTPSecret. NB: This IS populated in the places it is used.
I think I must have missed something obvious to get a result, here.
loSetup2FAData._s2FAValue = $#"otpauth://totp/{loUser.UserName}?secret={loUser.MakeTOTPSecret()}&digits=6&issuer={Booking.Library.Classes.Constants._sCompanyName}&period=60&algorithm=SHA1";
[AllowAnonymous]
public JsonResult _CheckTOTPCodeOnServer([FromBody] Booking.Site.Models.Shared.CheckTotpData loCheckTotpData)
{
string lsMessage = "<ul>";
try
{
string lsEmail = this.Request.HttpContext.Session.GetString("Buku_sEmail");
Booking.Data.DB.Extensions.IdentityExtend.User loUser = this._oDbContext.Users.Where(U => U.UserName.ToLower() == lsEmail.ToLower() || U.Email == lsEmail).FirstOrDefault();
if (loUser != null && loUser.Load(this._oDbContext) && loUser._gTOTPSecret != Guid.Empty)
{
OtpNet.Totp loTotp = new Totp(Booking.Library.Classes.Utility.StringToBytes(loUser.MakeTOTPSecret()), 60, OtpHashMode.Sha1, 6);
loTotp.ComputeTotp(DateTime.Now);
long lnTimeStepMatched = 0;
bool lbVerify = loTotp.VerifyTotp(loCheckTotpData._nTotp.ToString("000000"), out lnTimeStepMatched, new VerificationWindow(2, 2));
if (lbVerify)
{
lsMessage += "<li>Successfully validated Totp code</li>";
lsMessage += "<li>Save is now activated</li>";
return this.Json(new { bResult = true, sMessage = lsMessage + "</ul>" });
}
}
}
catch (Exception loException)
{
lsMessage += "<li>" + Booking.Library.Classes.Utility.MakeExceptionMessage(true, loException, "\r\n", "_CheckTOTPCodeOnServer") + "</li>";
}
lsMessage += "<li>Unsuccessfully validated Totp code</li>";
return this.Json(new { bResult = false, sMessage = lsMessage + "</ul>" });
}
public string MakeTOTPSecret()
{
string lsReturn = String.Empty;
try
{
using (SHA1Managed loSha1 = new SHA1Managed())
{
var loHash = loSha1.ComputeHash(Encoding.UTF8.GetBytes(this._gTOTPSecret.ToString()));
var loSb = new StringBuilder(loHash.Length * 2);
foreach (byte b in loHash)
{
loSb.Append(b.ToString("X2"));
}
lsReturn = loSb.ToString();
}
}
catch (Exception loException)
{
Booking.Library.Classes.Utility.MakeExceptionMessage(true, loException, "\r\n", "Identity.MakeSHA1Secret");
}
return lsReturn;
}
I am using AEM 6.1 with Maven as the build manager. I have updated the .m2 local folder with the unobfuscated UberJar provided by Adobe. I am getting the following error:
ERROR [JobHandler: /etc/workflow/instances/server0/2016-07-15/model_157685507700064:/content/myApp/testing/wf_test01]
com.adobe.granite.workflow.core.job.JobHandler Process implementation
not found: com.myApp.workflow.ActivatemyAppPageProcess
com.adobe.granite.workflow.WorkflowException: Process implementation
not found: com.myApp.workflow.ActivatemyAppPageProcess at
com.adobe.granite.workflow.core.job.HandlerBase.executeProcess(HandlerBase.java:197)
at
com.adobe.granite.workflow.core.job.JobHandler.process(JobHandler.java:232)
at
org.apache.sling.event.impl.jobs.JobConsumerManager$JobConsumerWrapper.process(JobConsumerManager.java:512)
at
org.apache.sling.event.impl.jobs.queues.JobRunner.run(JobRunner.java:205)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
The UberJar does not seem to have the com.adobe.granite.workflow.core.job package. Is there any way to resolve this issue?
The .execute method for the process step ActivatemyAppPageProcess:
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException {
Session participantSession = null;
Session replicationSession = null;
// ResourceResolver resourceResolver = null;
try {
log.info("Inside ActivatemyAppPageProcess ");
Session session = workflowSession.getSession();
if (replicateAsParticipant(args)) {
String approverId = resolveParticipantId(workItem, workflowSession);
if (approverId != null) {
participantSession = getParticipantSession(approverId, workflowSession);
}
}
if (participantSession != null)
replicationSession = participantSession;
else {
replicationSession = session;
}
WorkflowData data = workItem.getWorkflowData();
String path = null;
String type = data.getPayloadType();
if ((type.equals("JCR_PATH")) && (data.getPayload() != null)) {
String payloadData = (String) data.getPayload();
if (session.itemExists(payloadData))
path = payloadData;
}
else if ((data.getPayload() != null) && (type.equals("JCR_UUID"))) {
Node node = session.getNodeByUUID((String) data.getPayload());
path = node.getPath();
}
ReplicationOptions opts = null;
String rev = (String) data.getMetaDataMap().get("resourceVersion", String.class);
if (rev != null) {
opts = new ReplicationOptions();
opts.setRevision(rev);
}
opts = prepareOptions(opts);
if (path != null) {
ResourceCollection rcCollection =
ResourceCollectionUtil
.getResourceCollection(
(Node) this.admin.getItem(path),
(ResourceCollectionManager) this.rcManager);
boolean isWFPackage = isWorkflowPackage(path, resolverFactory, workflowSession);
List<String> paths = getPaths(path, rcCollection);
for (String aPath : paths)
if (canReplicate(replicationSession, aPath)) {
if (opts != null) {
if (isWFPackage) {
setRevisionForPage(aPath, opts, data);
}
this.replicator
.replicate(replicationSession,
getReplicationType(),
aPath,
opts);
} else {
this.replicator
.replicate(replicationSession,
getReplicationType(),
aPath);
}
} else {
log.debug(session.getUserID() + " is not allowed to replicate " + "this page/asset " + aPath + ". Issuing request for 'replication");
Dictionary properties = new Hashtable();
properties.put("path", aPath);
properties.put("replicationType", getReplicationType());
properties.put("userId", session.getUserID());
Event event = new Event("com/day/cq/wcm/workflow/req/for/activation", properties);
this.eventAdmin.sendEvent(event);
}
} else {
log.warn("Cannot activate page or asset because path is null for this workitem: " + workItem.toString());
}
} catch (RepositoryException e) {
throw new WorkflowException(e);
} catch (ReplicationException e) {
throw new WorkflowException(e);
} finally {
if ((participantSession != null) && (participantSession.isLive())) {
participantSession.logout();
participantSession = null;
}
}
}
com.adobe.granite.workflow.core.job is not exported in AEM at all. That means, you cannot use it because it is invisible to your code.
The com.adobe.granite.workflow.core bundle does only export com.adobe.granite.workflow.core.event.
If you work with the AEM workflows, you should stick to the com.adobe.granite.workflow.api bundle.
The following packages are exported in this bundle and therefore useable:
com.adobe.granite.workflow,version=1.0.0
com.adobe.granite.workflow.collection,version=1.1.0
com.adobe.granite.workflow.collection.util,version=1.0.0
com.adobe.granite.workflow.event,version=1.0.0
com.adobe.granite.workflow.exec,version=1.0.0
com.adobe.granite.workflow.exec.filter,version=1.0.0
com.adobe.granite.workflow.job,version=1.0.0
com.adobe.granite.workflow.launcher,version=1.0.0
com.adobe.granite.workflow.metadata,version=1.0.0
com.adobe.granite.workflow.model,version=1.0.0
com.adobe.granite.workflow.rule,version=1.0.0
com.adobe.granite.workflow.serialization,version=1.0.0
com.adobe.granite.workflow.status,version=1.0.0
Even if the uber.jar has the packages , if you look on your AEM instance on /system/console/bundles and click on the com.adobe.granite.workflow.core package, you will see that in "exported packages" there is no com.adobe.granite.workflow.core.job available. So even if your IDE, Maven and/or Jenkins can handle it, AEM will not be able to execute your code.
In AEM you can only use packages that are exported in one of the available bundles or that are included in your bundle - what would be a bad idea. You would then have two versions of the same code and that will lead to further problems.
Having seen the code I would say there's another problem here. And solving that one will help you get rid off the other one, too.
You try to start another WF (request for activation) for a path that is already used in a workflow.
You have to terminate the current workflow instance to be able to do this.
An example for a clean way to do this would be:
Workflow workflow = workItem.getWorkflow();
WorkflowData wfData = workflow.getWorkflowData();
workflowSession.terminateWorkflow(workflow);
Map<String, Object> paramMap = new HashMap<String, Object>();
if (!StringUtils.isEmpty(data.getNextParticipantUid())) {
paramMap.put("nextParticipant", "admin");
}
workflowSession.startWorkflow(
workflowSession.getModel(WORKFLOW_MODEL_PATH, wfData, paramMap);
The possible reason for the error could be that your workflow process com.myApp.workflow.ActivatemyAppPageProcess service/component is not active because of which its not bound to JobHandler's list of available processes thus causing this exception.
Can you check in /system/console/components that your custom process component is active? If not then you will have to resolve the dependency which is causing the service/component to be not available.
I am new to CRM and I have created a new AutoNumber plugin (actually modified an existing plugin).
I am having issues getting this plugin to work on the CRM side.
I have created the plugin, and I have created a CREATE step. I am confused with the IMAGE creation, and how I need to go about doing this.
Also, I am using the localContext.Trace and I am not sure where to view this information.
Can anyone help me with understanding the exact steps I need to follow to implement this plugin. I will include my code here in case I am doing something wrong. Again, this was a working plugin and I just modified it. I tried to follow the pattern used by the previous developer.
FYI -- I have purchased the CRM Solution Manager utility to help with the deployment process, but still not having any luck.
Thanks in advance for your time.
Here is the code..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IccPlugin.ProxyClasses;
using IccPlugin.ProxyClasses.ProxyClasses;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
namespace IccPlugin {
public class ProgramReportAutoNumber : PluginBase {
private readonly string imageAlias = "ProgramReport";
private new_programreport preImage { get; set; }
private new_programreport postImage { get; set; }
private new_programreport targetEntity { get; set; }
private readonly string imageAlias_program = "Program";
private new_program preImage_program { get; set; }
private new_program postImage_program { get; set; }
private new_program targetEntity_program { get; set; }
public ProgramReportAutoNumber(string unsecure, string secure)
: base(typeof(ProgramReportAutoNumber), unsecure, secure) {
base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)CrmPluginStepStage.PreOperation, "Create", "new_programreport", new Action<LocalPluginContext>(Execute)));
//base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)CrmPluginStepStage.PostOperation, "Update", "new_programreport", new Action<LocalPluginContext>(Execute)));
//base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)CrmPluginStepStage.PostOperation, "Delete", "new_programreport", new Action<LocalPluginContext>(Execute)));
}
protected void Execute(LocalPluginContext localContext) {
if (localContext == null) {
throw new ArgumentNullException("localContext");
}
IPluginExecutionContext context = localContext.PluginExecutionContext;
if (context.PreEntityImages.Contains(imageAlias) && (context.PreEntityImages[imageAlias] is Entity)) {
preImage = new new_programreport((Entity)context.PreEntityImages[imageAlias]);
}
if (context.PostEntityImages.Contains(imageAlias) && (context.PostEntityImages[imageAlias] is Entity)) {
postImage = new new_programreport((Entity)context.PostEntityImages[imageAlias]);
}
if (context.PreEntityImages.Contains(imageAlias_program) && (context.PreEntityImages[imageAlias_program] is Entity)) {
preImage_program = new new_program((Entity)context.PreEntityImages[imageAlias_program]);
}
if (context.PostEntityImages.Contains(imageAlias_program) && (context.PostEntityImages[imageAlias_program] is Entity)) {
postImage_program = new new_program((Entity)context.PostEntityImages[imageAlias_program]);
}
if (context.InputParameters.Contains("Target") && (context.InputParameters["Target"] is Entity)) {
targetEntity = new new_programreport((Entity)context.InputParameters["Target"]);
}
switch (context.MessageName) {
case "Create":
HandleCreate(localContext);
break;
case "Update":
HandleUpdate(localContext);
break;
case "Delete":
HandleDelete(localContext);
break;
default:
throw new ArgumentException("Invalid Message Name: " + context.MessageName);
}
}
private void HandleDelete(LocalPluginContext localContext) {
localContext.Trace("START - IccPlugin.ProgramReport.AutoNumber.HandleDelete");
try {
if (preImage == null) {
throw new Exception("IccPlugin.ProgramReport.AutoNumber.HandleDelete: preImage is null, unable to process the delete message.");
}
// TODO: Add code here to implement delete message.
} catch (Exception ex) {
localContext.Trace(String.Format("IccPlugin.ProgramReport.AutoNumber.HandleDelete: Exception while processing the delete message, Error Message: {0}", ex.Message), ex);
throw ex;
} finally {
localContext.Trace("END - IccPlugin.ProgramReport.AutoNumber.HandleDelete");
}
return;
}
private void HandleUpdate(LocalPluginContext localContext) {
localContext.Trace("START - IccPlugin.ProgramReport.AutoNumber.HandleUpdate");
if (preImage == null) {
string msg = "IccPlugin.ProgramReport.AutoNumber.HandleUpdate : The Update step is not registered correctly. Unable to retrieve the pre-operation image using alias" + imageAlias;
localContext.Trace(msg);
throw new Exception(msg);
}
if (postImage == null) {
string msg = "IccPlugin.ProgramReport.AutoNumber.HandleUpdate : The Update step is not registered correctly. Unable to retrieve the post-operation image using alias" + imageAlias;
localContext.Trace(msg);
throw new Exception(msg);
}
if (preImage_program == null) {
string msg = "IccPlugin.Program.AutoNumber.HandleUpdate : The Update step is not registered correctly. Unable to retrieve the pre-operation image using alias" + imageAlias_program;
localContext.Trace(msg);
throw new Exception(msg);
}
if (postImage_program == null) {
string msg = "IccPlugin.Program.AutoNumber.HandleUpdate : The Update step is not registered correctly. Unable to retrieve the post-operation image using alias" + imageAlias_program;
localContext.Trace(msg);
throw new Exception(msg);
}
try {
// TODO: Add code here to implement update message.
} catch (Exception ex) {
localContext.Trace(String.Format("IccPlugin.ProgramReport.AutoNumber.HandleUpdate: Exception while processing the update message, Error Message: {0}", ex.Message), ex);
throw ex;
} finally {
localContext.Trace("END - IccPlugin.ProgramReport.AutoNumber.HandleUpdate");
}
return;
}
private void HandleCreate(LocalPluginContext localContext) {
localContext.Trace("START - IccPlugin.ProgramReport.AutoNumber.HandleCreate");
if (targetEntity == null) {
string msg = "IccPlugin.ProgramReport.AutoNumber.HandleCreate : The Create step is not registered correctly. Unable to retrieve the target entity using alias Target.";
localContext.Trace(msg);
throw new Exception(msg);
}
try {
// if the target entity does not have the new_filenumber attribute set we will set it now.
if (targetEntity.new_filenumber != null && targetEntity.new_filenumber != "") {
// log a warning message and do not change this value.
localContext.Trace("The Program Report being created already has a value for File Number, skipping the auto number assignment for this field.");
} else {
SetFileNumber(localContext);
}
if (targetEntity.new_name != null && targetEntity.new_name != "") {
localContext.Trace("The Program Report being created already has a value for Report Number, skipping the auto number assignment for this field.");
} else {
SetReportNumber(localContext);
}
} catch (Exception ex) {
localContext.Trace(String.Format("IccPlugin.ProgramReport.AutoNumber.HandleCreate: Exception while processing the create message, Error Message: {0}", ex.Message), ex);
throw ex;
} finally {
localContext.Trace("END - IccPlugin.ProgramReport.AutoNumber.HandleCreate");
}
return;
}
private void SetFileNumber(LocalPluginContext localContext) {
localContext.Trace("START - IccPlugin.ProgramReport.AutoNumber.SetFileNumber");
string s_new_filenumberformat = string.Empty;
string s_new_reportnumberprefix = string.Empty;
string s_new_filenumbercode = string.Empty;
try {
IOrganizationService service = localContext.OrganizationService;
string fileNumberValue = "";
emds_autonumbersequence fileNumberSequence = null;
// ##################################################################################################
// 05/02/2013 -- BEP -- Code added for the following change to the auto-number for file numbering
// ##################################################################################################
// 1 - Year/Month/Sequence
// [Year]-[Month]-[Sequence] = [Year] is the current year / [Month] is the current month / [Sequence] is a number series for each Year & Month and resets to 1 when the Month changes
// 2 - Year/PMG/Sequence - PMG
// [Year]-[PMGProductType][Sequence] = [Year] is the current year / [PMGProductType] is 1st letter from the PMG Product Type on the Program Report / [Sequence] is a single number series for this Format
// 3 - Year/Letter/Sequence - ESL,VAR
// [Year]-[FileCode][Sequence] = [Year] is the current year / [FileCode] is from a new field on the Program entity / [Sequence] is a number series for each Format & File Code
// ##################################################################################################
localContext.Trace("Look at the File Number Format to determine which format to use for the Auto-Number, will default to 1 if not set");
if (targetEntity_program.new_filenumberformat.ToString() != "") {
localContext.Trace("A value was set for the new_filenumberformat field, so we will be using this value.");
s_new_filenumberformat = targetEntity_program.new_filenumberformat.ToString();
} else {
localContext.Trace("A value was NOT set for the new_filenumberformat field, so we will be using 1 as the default.");
s_new_filenumberformat = "1";
}
localContext.Trace("File Number Format Being Used = " + s_new_filenumberformat);
switch (s_new_filenumberformat) {
case "1":
#region File Format #1
fileNumberValue = String.Format("{0}-{1}", DateTime.Now.ToString("yy"), DateTime.Now.ToString("MM"));
localContext.Trace("Building QueryExpression to retrieve FileNumber Sequence record.");
QueryExpression qeFileNumberSequence_1 = new QueryExpression(BaseProxyClass.GetLogicalName<emds_autonumbersequence>());
qeFileNumberSequence_1.ColumnSet = new ColumnSet(true);
qeFileNumberSequence_1.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_entitylogicalname, ConditionOperator.Equal, BaseProxyClass.GetLogicalName<new_programreport>());
qeFileNumberSequence_1.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_attributelogicalname, ConditionOperator.Equal, new_programreport.Properties.new_filenumber);
qeFileNumberSequence_1.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_prefix, ConditionOperator.Equal, fileNumberValue);
localContext.Trace("Getting FileNumber sequence record.");
List<emds_autonumbersequence> lFileNumberSequences_1 = service.RetrieveProxies<emds_autonumbersequence>(qeFileNumberSequence_1);
if (lFileNumberSequences_1 == null || lFileNumberSequences_1.Count == 0) {
localContext.Trace("No FileNumber sequence record was returned, creatign a new one.");
// no matching sequence records. Lets start a new sequence index record for this month and year.
fileNumberSequence = new emds_autonumbersequence();
fileNumberSequence.emds_attributelogicalname = new_programreport.Properties.new_filenumber;
fileNumberSequence.emds_entitylogicalname = BaseProxyClass.GetLogicalName<new_programreport>();
fileNumberSequence.emds_index = 1;
fileNumberSequence.emds_prefix = fileNumberValue;
fileNumberSequence.emds_name = String.Format("File Number Sequence For: {0}", fileNumberValue);
fileNumberSequence.Create(service);
} else {
localContext.Trace("A FileNumber sequence record was found, using it.");
// a file number sequence record was returned. Even if there happen to be multiple we are going to just use the first one returned.
fileNumberSequence = lFileNumberSequences_1[0];
}
// ###############################################################################
// 05/02/2013 -- BEP -- Changed the format from "###" to be "##" for seq number
// ###############################################################################
fileNumberValue = String.Format("{0}-{1:00}", fileNumberValue, fileNumberSequence.emds_index);
fileNumberSequence.emds_index++;
fileNumberSequence.Update(service);
#endregion
break;
case "2":
#region File Format #2
if (targetEntity_program.new_reportnumberprefix != null && targetEntity_program.new_reportnumberprefix != "") {
localContext.Trace("A value was set for the new_reportnumberprefix field, so we will be using this value.");
s_new_reportnumberprefix = targetEntity_program.new_reportnumberprefix;
} else {
localContext.Trace("A value was NOT set for the new_reportnumberprefix field, so we will be using P as the default.");
s_new_reportnumberprefix = "P";
}
fileNumberValue = String.Format("{0}-{1}", DateTime.Now.ToString("yy"), s_new_reportnumberprefix);
localContext.Trace("Building QueryExpression to retrieve FileNumber Sequence record.");
QueryExpression qeFileNumberSequence_2 = new QueryExpression(BaseProxyClass.GetLogicalName<emds_autonumbersequence>());
qeFileNumberSequence_2.ColumnSet = new ColumnSet(true);
qeFileNumberSequence_2.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_entitylogicalname, ConditionOperator.Equal, BaseProxyClass.GetLogicalName<new_programreport>());
qeFileNumberSequence_2.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_attributelogicalname, ConditionOperator.Equal, new_programreport.Properties.new_filenumber);
qeFileNumberSequence_2.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_prefix, ConditionOperator.Equal, "PMG");
localContext.Trace("Getting FileNumber sequence record.");
List<emds_autonumbersequence> lFileNumberSequences_2 = service.RetrieveProxies<emds_autonumbersequence>(qeFileNumberSequence_2);
if (lFileNumberSequences_2 == null || lFileNumberSequences_2.Count == 0) {
localContext.Trace("No FileNumber sequence record was returned, creatign a new one.");
// no matching sequence records. Lets start a new sequence index record for this month and year.
fileNumberSequence = new emds_autonumbersequence();
fileNumberSequence.emds_attributelogicalname = new_programreport.Properties.new_filenumber;
fileNumberSequence.emds_entitylogicalname = BaseProxyClass.GetLogicalName<new_programreport>();
fileNumberSequence.emds_index = 1;
fileNumberSequence.emds_prefix = "PMG";
fileNumberSequence.emds_name = String.Format("File Number Sequence For: {0}", fileNumberValue);
fileNumberSequence.Create(service);
} else {
localContext.Trace("A FileNumber sequence record was found, using it.");
// a file number sequence record was returned. Even if there happen to be multiple we are going to just use the first one returned.
fileNumberSequence = lFileNumberSequences_2[0];
}
fileNumberValue = String.Format("{0}-{1:0000}", fileNumberValue, fileNumberValue + fileNumberSequence.emds_index.ToString());
fileNumberSequence.emds_index++;
fileNumberSequence.Update(service);
#endregion
break;
case "3":
#region File Format #3
if (targetEntity_program.new_filenumbercode != null && targetEntity_program.new_filenumbercode != "") {
localContext.Trace("A value was set for the new_filenumbercode field, so we will be using this value.");
s_new_filenumbercode = targetEntity_program.new_filenumbercode;
} else {
localContext.Trace("A value was NOT set for the new_filenumbercode field, so we will be using L as the default.");
s_new_filenumbercode = "l";
}
fileNumberValue = String.Format("{0}-{1}", DateTime.Now.ToString("yy"), s_new_filenumbercode);
localContext.Trace("Building QueryExpression to retrieve FileNumber Sequence record.");
QueryExpression qeFileNumberSequence_3 = new QueryExpression(BaseProxyClass.GetLogicalName<emds_autonumbersequence>());
qeFileNumberSequence_3.ColumnSet = new ColumnSet(true);
qeFileNumberSequence_3.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_entitylogicalname, ConditionOperator.Equal, BaseProxyClass.GetLogicalName<new_programreport>());
qeFileNumberSequence_3.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_attributelogicalname, ConditionOperator.Equal, new_programreport.Properties.new_filenumber);
qeFileNumberSequence_3.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_prefix, ConditionOperator.Equal, fileNumberValue);
localContext.Trace("Getting FileNumber sequence record.");
List<emds_autonumbersequence> lFileNumberSequences_3 = service.RetrieveProxies<emds_autonumbersequence>(qeFileNumberSequence_3);
if (lFileNumberSequences_3 == null || lFileNumberSequences_3.Count == 0) {
localContext.Trace("No FileNumber sequence record was returned, creatign a new one.");
// no matching sequence records. Lets start a new sequence index record for this month and year.
fileNumberSequence = new emds_autonumbersequence();
fileNumberSequence.emds_attributelogicalname = new_programreport.Properties.new_filenumber;
fileNumberSequence.emds_entitylogicalname = BaseProxyClass.GetLogicalName<new_programreport>();
fileNumberSequence.emds_index = 1;
fileNumberSequence.emds_prefix = fileNumberValue;
fileNumberSequence.emds_name = String.Format("File Number Sequence For: {0}", fileNumberValue);
fileNumberSequence.Create(service);
} else {
localContext.Trace("A FileNumber sequence record was found, using it.");
// a file number sequence record was returned. Even if there happen to be multiple we are going to just use the first one returned.
fileNumberSequence = lFileNumberSequences_3[0];
}
fileNumberValue = String.Format("{0}-{1:0000}", fileNumberValue, fileNumberValue + fileNumberSequence.emds_index.ToString());
fileNumberSequence.emds_index++;
fileNumberSequence.Update(service);
#endregion
break;
default:
break;
}
targetEntity.new_filenumber = fileNumberValue;
} catch (Exception ex) {
localContext.Trace(String.Format("IccPlugin.ProgramReport.AutoNumber.SetFileNumber: Exception while setting the File Number value, Error Message: {0}", ex.Message), ex);
throw ex;
} finally {
localContext.Trace("END - IccPlugin.ProgramReport.AutoNumber.SetFileNumber");
}
}
private void SetReportNumber(LocalPluginContext localContext) {
localContext.Trace("START - IccPlugin.ProgramReport.AutoNumber.SetReportNumber");
string s_new_reportnumberprefix = string.Empty;
try {
IOrganizationService service = localContext.OrganizationService;
string reportNumberValue = "";
emds_autonumbersequence reportNumberSequence = null;
// ##################################################################################################
// 05/02/2013 -- BEP -- Code added for the following change to the auto-number for file numbering
// ##################################################################################################
// Currently the plugin uses the GP Class Id as the prefix for the Report Number.
// It now needs to use the Report Number Prefix field.
// ##################################################################################################
if (targetEntity_program.new_reportnumberprefix != null && targetEntity_program.new_reportnumberprefix != "") {
localContext.Trace("A value was set for the new_reportnumberprefix field, so we will be using this value.");
s_new_reportnumberprefix = targetEntity_program.new_reportnumberprefix;
} else {
localContext.Trace("A value was NOT set for the new_reportnumberprefix field, so we will be using P as the default.");
s_new_reportnumberprefix = "P";
}
localContext.Trace("Building QueryExpression to retrieve parent new_program record.");
// #################################################################################
// 05/02/2013 -- BEP -- The above code replaces the need to pull the GP Class ID
// #################################################################################
//new_program program = targetEntity.new_programid.RetrieveProxy<new_program>(service, new ColumnSet(true));
// going to assume that we were able to get the parent program record. If not an exception will be thrown.
// could add a check here and throw our own detailed exception if needed.
reportNumberValue = String.Format("{0}", s_new_reportnumberprefix); // using Trim just to be safe.
// now lets get the sequence record for this Report Number Prefix
QueryExpression qeReportNumberSequence = new QueryExpression(BaseProxyClass.GetLogicalName<emds_autonumbersequence>());
qeReportNumberSequence.ColumnSet = new ColumnSet(true);
qeReportNumberSequence.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_entitylogicalname, ConditionOperator.Equal, BaseProxyClass.GetLogicalName<new_programreport>());
qeReportNumberSequence.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_attributelogicalname, ConditionOperator.Equal, new_programreport.Properties.new_name);
qeReportNumberSequence.Criteria.AddCondition(emds_autonumbersequence.Properties.emds_prefix, ConditionOperator.Equal, reportNumberValue);
localContext.Trace("Getting Report Number sequence record.");
List<emds_autonumbersequence> lReportNumberSequences = service.RetrieveProxies<emds_autonumbersequence>(qeReportNumberSequence);
if (lReportNumberSequences == null || lReportNumberSequences.Count == 0) {
localContext.Trace("No Report Number sequence record was returned, creatign a new one.");
// no matching sequence records. Lets start a new sequence index record for this month and year.
reportNumberSequence = new emds_autonumbersequence();
reportNumberSequence.emds_attributelogicalname = new_programreport.Properties.new_name;
reportNumberSequence.emds_entitylogicalname = BaseProxyClass.GetLogicalName<new_programreport>();
reportNumberSequence.emds_index = 1;
reportNumberSequence.emds_prefix = reportNumberValue;
reportNumberSequence.emds_name = String.Format("Report Number Sequence For Report Number Prefix: {0}", reportNumberValue);
reportNumberSequence.Create(service);
} else {
localContext.Trace("A Report Number sequence record was found, using it.");
// a file number sequence record was returned. Even if there happen to be multiple we are going to just use the first one returned.
reportNumberSequence = lReportNumberSequences[0];
}
reportNumberValue = String.Format("{0}-{1}", reportNumberValue, reportNumberSequence.emds_index);
reportNumberSequence.emds_index++;
reportNumberSequence.Update(service);
targetEntity.new_name = reportNumberValue;
} catch (Exception ex) {
localContext.Trace(String.Format("IccPlugin.ProgramReport.AutoNumber.SetReportNumber: Exception while setting the File Number value, Error Message: {0}", ex.Message), ex);
throw ex;
} finally {
localContext.Trace("END - IccPlugin.ProgramReport.AutoNumber.SetReportNumber");
}
}
}
}
This is specifically to response to:
I am using the localContext.Trace and I am not sure where to view this
information
From the MSDN; Debug a Plug-In - Logging and Tracing
During execution and only when that plug-in passes an exception back
to the platform at run-time, tracing information is displayed to the
user. For a synchronous registered plug-in, the tracing information is
displayed in a dialog box of the Microsoft Dynamics CRM web
application. For an asynchronous registered plug-in, the tracing
information is shown in the Details area of the System Job form in the
web application.
I am using EWS and wish to obtain the global address list from exchange for the company. I know how to retrieve the personal contact list.
All the samples in the API documentation deal with updating user information but not specifically how to retrieve them.
I've even tried the following to list the folders but it doesn't yeild the correct results.
private static void ListFolder(ExchangeService svc, FolderId parent, int depth) {
string s;
foreach (var v in svc.FindFolders(parent, new FolderView(int.MaxValue))) {
Folder f = v as Folder;
if (f != null) {
s = String.Format("[{0}]", f.DisplayName);
Console.WriteLine(s.PadLeft(s.Length + (depth * 2)));
ListFolder(svc, f.Id, depth + 1);
try {
foreach (Item i in f.FindItems(new ItemView(20))) {
Console.WriteLine(
i.Subject.PadLeft(i.Subject.Length + ((depth + 1) * 2)));
}
} catch (Exception) {
}
}
}
}
While the question has already been raised (How to get contact list from Exchange Server?) this question deals specifically with using EWS to get the global address list while this question asks for advice on a general level.
you may got ItemType objects in a specifiedfolder with the code snippet below
and then cast ItemType objects to ContactItemType (for contact objects) ....
/// <summary>
/// gets list of ItemType objects with maxreturncriteria specicification
/// </summary>
/// <param name="esb">ExchangeServiceBinding object</param>
/// <param name="folder">FolderIdType to get items inside</param>
/// <param name="maxEntriesReturned">the max count of items to return</param>
public static List<ItemType> FindItems(ExchangeServiceBinding esb, FolderIdType folder, int maxEntriesReturned)
{
List<ItemType> returnItems = new List<ItemType>();
// Form the FindItem request
FindItemType request = new FindItemType();
request.Traversal = ItemQueryTraversalType.Shallow;
request.ItemShape = new ItemResponseShapeType();
request.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;
request.ParentFolderIds = new FolderIdType[] { folder };
IndexedPageViewType indexedPageView = new IndexedPageViewType();
indexedPageView.BasePoint = IndexBasePointType.Beginning;
indexedPageView.Offset = 0;
indexedPageView.MaxEntriesReturned = 100;
indexedPageView.MaxEntriesReturnedSpecified = true;
request.Item = indexedPageView;
FindItemResponseType response = esb.FindItem(request);
foreach (FindItemResponseMessageType firmtMessage in response.ResponseMessages.Items)
{
if (firmtMessage.ResponseClass == ResponseClassType.Success)
{
if (firmtMessage.RootFolder.TotalItemsInView > 0)
foreach (ItemType item in ((ArrayOfRealItemsType)firmtMessage.RootFolder.Item).Items)
returnItems.Add(item);
//Console.WriteLine(item.GetType().Name + ": " + item.Subject + ", " + item.DateTimeReceived.Date.ToString("dd/MM/yyyy"));
}
else
{
//handle error log here
}
}
return returnItems;
}
I just did a similiar thing. However, I was unable to get the list of contacts via Exchange since that only gets users that have mailboxes, and not necessarily all users or groups. I eventually ended up getting all the users via AD
here is code to get all the contacts in AD. All you need is the folderID of the global address list which can be gotten from using the ADSI.msc tool on your AD server and browsing to the Global address list folder, look at properties and grab the value of the "purported search". In my system the searchPath for the global address list is"(&(objectClass=user)(objectCategory=person)(mailNickname=)(msExchHomeServerName=))"
public List<ListItem> SearchAD(string keyword, XmlDocument valueXml)
{
List<ListItem> ewsItems = new List<ListItem>();
using (DirectoryEntry ad = Utils.GetNewDirectoryEntry("LDAP://yourdomain.com"))
{
Trace.Info("searcherをつくる");
using (DirectorySearcher searcher = new DirectorySearcher(ad))
{
if (this.EnableSizeLimit)
{
searcher.SizeLimit = GetMaxResultCount();
if (Utils.maxResultsCount > 1000)
{
searcher.PageSize = 100;
}
}
else
{
searcher.SizeLimit = 1000;
searcher.PageSize = 10;
}
string sisya = Utils.DecodeXml(valueXml.SelectSingleNode("Folder/SearchPath").InnerText); //this is the folder to grab your contacts from. In your case Global Address list
//Container
if(String.IsNullOrEmpty(sisya))
{
return null;
}
keyword = Utils.EncodeLdap(keyword);
string text = Utils.DecodeXml(valueXml.SelectSingleNode("Folder/Text").InnerText);
searcher.Filter = this.CreateFilter(keyword, sisya);
searcher.Sort = new SortOption("DisplayName", System.DirectoryServices.SortDirection.Ascending);
//一つのPropertyをロードすると、全Propertyを取らないようになる
searcher.PropertiesToLoad.Add("SAMAccountName"); //どのPropertyでもいい。
SearchResultCollection searchResults = searcher.FindAll();
foreach (SearchResult searchResult in searchResults)
{
//ListItem contact = null;
using (DirectoryEntry userEntry = searchResult.GetDirectoryEntry())
{
try
{
string schemaClassName = userEntry.SchemaClassName;
switch (schemaClassName)
{
case "user":
case "contact":
string fname = userEntry.Properties["GivenName"].Value == null ? "" : userEntry.Properties["GivenName"].Value.ToString();
string lname = userEntry.Properties["sn"].Value == null ? "" : userEntry.Properties["sn"].Value.ToString();
string dname = userEntry.Properties["DisplayName"][0] == null ? lname + " " + fname : userEntry.Properties["DisplayName"][0].ToString();
//No Mail address
if ((userEntry.Properties["mail"] != null) && (userEntry.Properties["mail"].Count > 0))
{
string sAMAccountName = "";
if(userEntry.Properties["SAMAccountName"].Value != null){
sAMAccountName = userEntry.Properties["SAMAccountName"].Value.ToString();
}
else{
sAMAccountName = userEntry.Properties["cn"].Value.ToString();
}
string contactXml = Utils.ListViewXml(sAMAccountName, UserType.User, Utils.UserXml(fname, lname, userEntry.Properties["mail"].Value.ToString(), dname, null), ServerType.Ad);
ewsItems.Add(new ListItem(dname + "<" + userEntry.Properties["mail"].Value.ToString() + ">", contactXml));
}
else
{
ListItem contact = new ListItem(dname, null);
contact.Enabled = false;
ewsItems.Add(contact);
Trace.Info("追加できないユーザ: " + searchResult.Path);
}
break;
case "group":
ewsItems.Add(new ListItem(userEntry.Properties["DisplayName"].Value.ToString(), Utils.ListViewXml(userEntry.Properties["SAMAccountName"].Value.ToString(), UserType.Group, null, ServerType.Ad)));
break;
default:
userEntry.Properties["SAMAccountName"].Value.ToString());
ewsItems.Add(new ListItem(userEntry.Properties["name"].Value.ToString(), Utils.ListViewXml(userEntry.Properties["SAMAccountName"].Value.ToString(), UserType.Group, null, ServerType.Ad)));
break;
}
}
catch (Exception ex)
{
Trace.Error("User data取得失敗", ex);
}
}
}
searchResults.Dispose();
}
}
return ewsItems;
}