How to provide multiple mapping manager for solr multiple cores in SolrNet - solrnet

I have configured 2 solr cores and trying to map to 2 different classes thru solrnet. I'm currently using Ninject but willing to change to say Windsor if it's not possible in Ninject. I'm trying to use the AllPropertiesMappingManager for mapping. Since I need to set 2 different unique keys for 2 different cores I don't know how to do the same using AllPropertiesMappingManager.
Currently without using the Mapping manager I'm getting the error: Document is missing mandatory uniqueKey field: TranscriptId
EDIT: Error disappears after using attribute based mapping
var solrServers = new SolrServers {
new SolrServerElement {
Id = "markup",
Url = solrMarkupUrl,
DocumentType = typeof(SolrMarkup).AssemblyQualifiedName,
},
new SolrServerElement {
Id = "transcript",
Url = solrTranscriptUrl,
DocumentType = typeof(SolrTranscript).AssemblyQualifiedName,
}
};
kernel = new StandardKernel();
kernel.Load(new SolrNetModule(solrServers));
SolrMarkupCore = kernel.Get<ISolrOperations<SolrMarkup>>("markup");
SolrTranscriptCore = kernel.Get<ISolrOperations<SolrTranscript>>("transcript");

You can look at the SolrNet unit tests for Ninject with multiple cores - NinjectMultiCoreFixtures.cs for a working example.
Also, if you are not using the mapping manager are you useing Attribute based mapping to get things setup? Because you will still need to setup the mapping between your SolrMarkup and SolrTranscript classes fo things to work properly.

Related

How can I enable automatic slicing on Elasticsearch operations like UpdateByQuery or Reindex using the Nest client?

I'm using the Nest client to programmatically execute requests against an Elasticsearch index. I need to use the UpdateByQuery API to update existing data in my index. To improve performance on large data sets, the recommended approach is to use slicing. In my case I'd like to use the automatic slicing feature documented here.
I've tested this out in the Kibana dev console and it works beautifully. I'm struggling on how to set this property in code through the Nest client interface. here's a code snippet:
var request = new Nest.UpdateByQueryRequest(indexModel.Name);
request.Conflicts = Elasticsearch.Net.Conflicts.Proceed;
request.Query = filterQuery;
// TODO Need to set slices to auto but the current client doesn't allow it and the server
// rejects a value of 0
request.Slices = 0;
var elasticResult = await _elasticClient.UpdateByQueryAsync(request, cancellationToken);
The comments on that property indicate that it can be set to "auto", but it expects a long so that's not possible.
// Summary:
// The number of slices this task should be divided into. Defaults to 1, meaning
// the task isn't sliced into subtasks. Can be set to `auto`.
public long? Slices { get; set; }
Setting to 0 just throws an error on the server. Has anyone else tried doing this? Is there some other way to configure this behavior? Other APIs seem to have the same problem, like ReindexOnServerAsync.
This was a bug in the spec and an unfortunate consequence of generating this part of the client from the spec.
The spec has been fixed and the change will be reflected in a future version of the client. For now though, it can be set with the following
var request = new Nest.UpdateByQueryRequest(indexModel.Name);
request.Conflicts = Elasticsearch.Net.Conflicts.Proceed;
request.Query = filterQuery;
((IRequest)request).RequestParameters.SetQueryString("slices", "auto");
var elasticResult = await _elasticClient.UpdateByQueryAsync(request, cancellationToken);

Is it possible to track changes to Entity Metadata in Dynamics CRM?

Is there any way to track changes to Metadata, like new fields, new entities and so on?
It is difficult to control a very large project in the same environment, so sometimes there are some customization that should not be deployed to productions (Mostly are mistakes or test in a development environment).
And there is a way to know who did that customization?
I am looking to know every possible change, not any in particular.
You have to use the RetrieveMetadataChangesRequest and it is not possible to know who made the change.
This is available only from Microsoft Dynamics CRM 2011 Update Rollup 12
This request is intended to be used to cache information from the metadata and be able to work offline, but we can use it to track changes to metadata in complex projects and complex teams
Examples on internet are not very friendly so this is how you can use the request:
The request can be completed only with filling one parameter
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
ClientVersionStamp = null
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
The first time you executed this request ClientVersionStamp needs to be null, because there was no request made to the metadata before and there is no ClientVersionStamp. This parameter is the last time you query for metadata changes and if it is null it will bring all customization from all time, so probably this request won't complete on time so we need to tune up.
var EntityFilter = new MetadataFilterExpression(LogicalOperator.And);
EntityFilter.Conditions.Add(new MetadataConditionExpression("SchemaName", MetadataConditionOperator.Equals, "ServiceAppointment"));
var entityQueryExpression = new EntityQueryExpression()
{
Criteria = EntityFilter
};
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = null
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
This will query all metadata changes for "ServiceAppointment", feel free to use the entity you want, but what we need is the ServerTimeStamp from the response, it will looks like "22319800!09/13/2017 16:17:46", if you try to send this time stamp first, it will throw an exception, so it is necessary to query first to get a server time stamp.
Now you can use the request and the time stamp to retrieve all new changes since "22319800!09/13/2017 16:17:46"
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = #"22319800!09/13/2017 16:17:46"
};
var response = (RetrieveMetadataChangesResponse)service.Execute(req);
You can filter the query to match your needs, only search for specific entities, labels, relationship, keys and attributes or specific properties.
EntityQueryExpression entityQueryExpression = new EntityQueryExpression()
{
Criteria = EntityFilter,
Properties = EntityProperties,
RelationshipQuery = new RelationshipQueryExpression()
{
Properties = RelationshipProperties,
Criteria = RelationshipFilter
},
AttributeQuery = new AttributeQueryExpression()
{
Properties = AttributeProperties,
Criteria = AttributeFilter
}
};
Use this request and implement it the way you need.
A couple more options:
Register a plugin on Publish and Publish All, and track who did
the publish and when. That may help you narrow down who was making
changes, although someone could technically make a change without
publishing it, so not perfect information.
If you're using Dynamics OnPremise, the Metadata tables sometimes store information about who made a change that is not visible through a Metadata retrieve. I've found this to be very spotty though, not all Metadata has a Modified By user stored.

CRM do not support direct update of Entity Reference properties, Use Navigation properties instead

I am using Ms Dynamic Web Api with Simple OData. I need to add new record for link entities.
I am using the below code snip and refer the documentation on
https://github.com/object/Simple.OData.Client/wiki/Adding-entries-with-links
var newContactData = await _oDataClient
.For<Contacts>()
.Set(new
{
firstname = contactData.ContatDetails.firstname,
lastname = contactData.ContatDetails.lastname,
emailaddress1 = contactData.ContatDetails.emailaddress1
})
.InsertEntryAsync(true);
var newContactLink = await _oDataClient.For<New_project_contactses>()
.Set(new
{
_new_contact_project_name_new_value = contactData.ContatDetailsLink._new_contact_project_name_new_value,
new_project_contactsid = new Guid("0eb46b24-21a2-e611-80eb-c4346bc5b2d4"),
new_contact_type = contactData.ContatDetailsLink.new_contact_type,
})
.InsertEntryAsync(resultRequired: true);
i am getting exception
CRM do not support direct update of Entity Reference properties, Use
Navigation properties insteadS
Well, it is possible, but you need to use the special "#odata.bind" syntax to update your single-navigation properties.
For example, to update an account so that it references an existing primarycontactid, you can use a PATCH operation to the /api/data/v8.2/accounts endpoint with the following body:
{
"name":"Sample Account",
"primarycontactid#odata.bind":"/contacts(00000000-0000-0000-0000-000000000001)"
}
See https://msdn.microsoft.com/en-us/library/gg328090.aspx#Anchor_3 (it is discussed in terms of creating an entity, but it works for updating as well).
I figure out the issue With Dynamc CRM you cannot directly update reference entities Field. You can identify reference entity properties start with "_".

Load up properties using polymorphism in spring boot

I am looking to load 3 separate properties for 3 supported country codes (example: us, uk, de) in a spring boot app.
For this, I need to load the appropriate property file for a country code specified in each of the messages that I am trying to process.
Currently, I get the country code info as a string from the message and load the properties file if that country code is present in my HashMap.
usPropsInfo, ukPropsInfo, dePropsInfo are loaded in the configuration class using PropertySourcesPlaceholderConfigurer
Map<String, Properties> countryCodeProps = new HashMap<String, Properties>();
countryCodeProps.put ("us", usPropsInfo);
countryCodeProps.put ("uk", ukPropsInfo);
countryCodeProps.put ("de", dePropsInfo);
String countryCode = message.getStringProperty("country");
if(null!=countryCode && countryCode.trim().size()>0
{
if(countryCodeProps.containsKey(countryCode)){
Properties props = countryCodeProps.get(countryCode);
}
}
Is there a better way to achieve this? Can I achieve this using Polymorphism in spring boot?
Thanks,
Abhi

Using AWS API/SDK to Register new EC2 Instances with Existing Elastic Load Balancer - is it possible?

I'm working on using the .Net SDK to help automate the deployment of an application into Windows EC2 instances. The process I want to achieve is:
Create a new EC2 instance - this
"bootstraps" itself by loading in
the new application version using a
service.
Ensure the new instance is in the
'running' state
Run some simple acceptance tests on
the new instance.
Register the new instance with an
existing Elastic Load balancer that
has an instance running the old
version of the application.
When the new instance is registered
with the load balancer, de-register
the old instance.
Stop the old EC2 instance.
I've managed to get steps 1 and 2 working, and I'm pretty confident about 3 and 6.
To do this I've been writing a simple C# console app that uses the AWS .Net SDK v1.3.2 to make the various API calls.
However, when I get to step 4 I cannot get the new instance registered with the load balancer. Here is my code:
public IList<Instance> PointToNewInstance(string newInstanceId)
{
var allInstances = new List<Instance>();
using (var elbClient = ClientUtilities.GetElbClient())
{
try
{
var newInstances = new List<Instance> {new Instance(newInstanceId)};
var registInstancesRequest = new RegisterInstancesWithLoadBalancerRequest
{
LoadBalancerName = LoadBalancerName,
Instances = newInstances
};
var registerReponse = elbClient.RegisterInstancesWithLoadBalancer(registInstancesRequest);
allInstances = registerReponse.RegisterInstancesWithLoadBalancerResult.Instances;
var describeInstanceHealthRequest = new DescribeInstanceHealthRequest
{
Instances = newInstances
};
DescribeInstanceHealthResponse describeInstanceHealthResponse;
do
{
describeInstanceHealthResponse = elbClient.DescribeInstanceHealth(describeInstanceHealthRequest);
} while (describeInstanceHealthResponse.DescribeInstanceHealthResult.InstanceStates[0].State == "OutOfService");
_log.DebugFormat("New instance [{0}] now in service - about to stop remove old instance", newInstanceId);
if (allInstances.Any(i => i.InstanceId != newInstanceId))
{
elbClient.DeregisterInstancesFromLoadBalancer(new DeregisterInstancesFromLoadBalancerRequest
{
Instances = allInstances.Where(i => i.InstanceId != newInstanceId).ToList(),
LoadBalancerName = LoadBalancerName
});
foreach (var instance in allInstances.Where(i => i.InstanceId != newInstanceId).ToList())
{
_log.DebugFormat("Instance [{0}] has now been de-registered from load-balancer [{1}]", instance.InstanceId, LoadBalancerName);
}
}
}
catch (Exception exception)
{
_log.Error(exception);
}
}
return allInstances.Where(i => i.InstanceId != newInstanceId).ToList();
}
The code just freezes at this line:
var registerReponse = elbClient.RegisterInstancesWithLoadBalancer(registInstancesRequest);
When I looked in more detail at the documention (relevant documentation here) I noticed this line:
NOTE: In order for this call to be
successful, the client must have
created the LoadBalancer. The client
must provide the same account
credentials as those that were used to
create the LoadBalancer.
Is it actually possible to use the API to register new instances with an existing load balancer?
All of that is easy to implement. Use Auto Scaling. Use API.
As Roman mentions, it sounds like Auto Scaling is a good way for you to go, it may not solve all of your problems but its certainly a good starting point:
-an auto scaling group can be tied to a load balancer, e.g. ill have x healthy instances
-new instances are automatically added to the load balancer (no traffic will be sent until it passed the health check)
-you can define custom health checks, such as ping http://hostname/isalive just have your instance respond to these requests once its passes step 3
-you can define scaling policies but by default if you're over capacity the oldest instances will be killed
-you don't mention the use case of the app but if you don't want a public facing address you can use an internal load balancer that doesn't take any traffic, just looks after the health check
-where possible you should always use least privilege principles for security, with your method you're going to have to give every instance a lot of power to control other instances, whether through mistake or abuse this can go wrong very easily

Resources