Accessing user attributes using UserAccessor - s4sdk

The class com.sap.cloud.sdk.cloudplatform.security.user.UserAccessor allows to me to retrieve the current user and it's attributes.
For example:
Optional<UserAttribute> optionalfirstName = user.getAttribute("firstname");
UserAttribute ua = optionalfirstName.get();
Once I have retrieved the UserAttribute, it has two properites "Name" and "Value". However there is no method available to get the Value. How can I access the value?

Depending on the SAP CP environment you are using, the UserAttribute is an instance of:
SimpleUserAttribute<String> on Neo
CollectionUserAttribute<String> on Cloud Foundry
You can access the respective values by type-casting to the required instance:
if( ua instanceof SimpleUserAttribute ) {
String value = (String) ((SimpleUserAttribute<?>)ua).getValue();
}
else if ( ua instanceof CollectionUserAttribute ) {
Collection<?> values = ((CollectionUserAttribute<?>)ua).getValues();
}
Note: We plan to simplify this in future releases of the SDK so that StringUserAttribute and StringCollectionUserAttribute instances are returned for more convenient consumption.

Related

Dynamics 365 API link between ActivityPointer and activitytypecode global option set

I am reading data from the ActivityPointer entity in Dynamics 365 via the API and I want to link the activitytypecode field value to the activitypointer_activitytypecode global option set, which I believe is the correct one. However the values don't seem to match. In the ActivityPointer.activitytypecode field I have values such as:
phonecall
bulkoperation
email
appointment
task
But those values don't appear in the option set definition, using this query: GlobalOptionSetDefinitions(Name='activitypointer_activitytypecode')
The option set has the code values (e.g. 4202 for Email) and the different descriptions in all languages, but nothing matches back to the values on ActivityPointer
Optionset is just key value pairs (4202: Email and so on), If you want to get the formatted text value of optionset (Email, Fax, etc) from your web api query results - then you have to use activitytypecode#OData.Community.Display.V1.FormattedValue to get it. Read more
I recommend this article for complete understanding of CRM activities.
If you are looking for the code integer value in your resultset, that seems to be an issue and the result is not the expected one - old SO thread
The problem is that if you are reading activitytypecode in code, then you will know that you get a string value. This is the logical name of the activity entity, e.g. "email", "phonecall" etc.
If you look at the definition of activitytypecode in Power Apps then it shows it as "Entity name" (i.e. text) but using the classic solution editor it shows as the global activitypointer_activitytypecode option set, which contains values for "Email", "Phone Call" etc.
I am sure that there should be a simple way of converting from activitytypecode (i.e. entity name) to activitypointer_activitytypecode (i.e. option set), but I've yet to find it.
What I am doing is retrieving the global activitypointer_activitytypecode option set, so I have access to all of the text values. Then retrieve details about the entity indicated by activitytypecode, specifically what is of interesting is the display name. Then loop through the option set looking for a case-insensitive match on display name.
This is my C# code:
public int? GetActivityType(IOrganizationService service, string activityTypeCode)
{
// Get all activity types.
var optionSetRequest = new RetrieveOptionSetRequest()
{
Name = "activitypointer_activitytypecode"
};
var optionSetResponse = (RetrieveOptionSetResponse)service.Execute(optionSetRequest);
var optionSetMetadata = (OptionSetMetadata)optionSetResponse.OptionSetMetadata;
var optionValues = new Dictionary<string, int?>(StringComparer.OrdinalIgnoreCase);
foreach (var option in optionSetMetadata.Options)
{
foreach (var optionLabel in option.Label.LocalizedLabels)
{
optionValues[optionLabel.Label] = option.Value;
}
}
// Get the display name for the activity.
var retrieveEntityRequest = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.Entity,
LogicalName = activityTypeCode
};
var retrieveEntityResponse = (RetrieveEntityResponse)service.Execute(retrieveEntityRequest);
LocalizedLabelCollection entityLabels = retrieveEntityResponse.EntityMetadata.DisplayName.LocalizedLabels;
// Look up the display name in the option set values.
foreach (var entityLabel in entityLabels)
{
if (optionValues.TryGetValue(entityLabel.Label, out int? value))
{
return (Schema.GlobalOptionSet.ActivityType?)value;
}
}
// If we get here then we've failed.
return null;
}
That is making two API calls, so best avoided in any situations where performance might be an issue. I'm not saying the code is perfect, but it hasn't let me down yet. Even so, I would recommend making do with the logical names provided by activitytypecode if you can.

Get specific CRM organization instead of all

There are multiple organizations on a CRM on-prem environment. I have stored DiscoveryService URL and organization name in a configuration file.
I want to get an Organization instance for a specific organization using organization name available in the configuration file, instead of loading all organizations.
something similar to,
select organizations from Organizations where orgName = 'XYZ'
Currently, I am using the below code, which is taking more than 3 seconds to retrieve an instance.
private OrganizationDetail DiscoverOrganization(Uri discoveryUri, string organizationName, ClientCredentials lclClientCredentials)
{
DiscoveryServiceProxy serviceProxy;
using (serviceProxy = new DiscoveryServiceProxy(discoveryUri, null, lclClientCredentials, null))
{
IDiscoveryService service = serviceProxy;
var orgsRequest = new RetrieveOrganizationsRequest() { AccessType = EndpointAccessType.Default, Release = OrganizationRelease.Current };
var organizations = (RetrieveOrganizationsResponse)service.Execute(orgsRequest);
return organizations.Details.FirstOrDefault(x => x.UniqueName.ToLower() == organizationName.ToLower());
}
}
You can try web api version as well. Read more
GET https://dev.{servername}/api/discovery/v9.0/Instances(UniqueName='myorg')

Created By LoginName (ID) with SPMetal in SharePoint 2010

I'm working with the OOB blog sites in SP2010. I'm using SPMetal to generate entity classes for the Posts list (among others). I've used a parameters.xml file to get the other columns that I need that aren't included by default.
One of the things that I want to do is to get the users' My Site url. I am able to do this with CAML relatively easily. However I need to do it using Linq. I can't figure out how to get the login id (i.e. domain\id) for the Author Field. I've looked through the Contact content type and it doesn't appear to have anything to help.
Has anyone run across this or gotten the login id for a user with SPMetal?
if you create Entity of Posts list using SPMetel.exe and if in Posts list having Suppose Field Type is User than automatically return two methods of like LookupId and LookupValue.
In my case : I have take promoterid As a Field name in Posts list in in my Entity having two method
private System.Nullable<int> _promoterId;
private string _promoter;
[Microsoft.SharePoint.Linq.ColumnAttribute(Name="promoterid", Storage="_promoterId", FieldType="User", IsLookupId=true)]
public System.Nullable<int> PromoterId {
get {
return this._promoterId;
}
set {
if ((value != this._promoterId)) {
this.OnPropertyChanging("PromoterId", this._promoterId);
this._promoterId = value;
this.OnPropertyChanged("PromoterId");
}
}
}
[Microsoft.SharePoint.Linq.ColumnAttribute(Name="promoterid", Storage="_promoter", ReadOnly=true, FieldType="User", IsLookupValue=true)]
public string Promoter {
get {
return this._promoter;
}
set {
if ((value != this._promoter)) {
this.OnPropertyChanging("Promoter", this._promoter);
this._promoter = value;
this.OnPropertyChanged("Promoter");
}
}
}
than after i can able to use using linq query
i.e
SPWeb oWebsiteRoot = SPContext.Current.Web;
EntitiesDataContext objent = new EntitiesDataContext(oWebsiteRoot.Url);
EntityList<PostsItem> evnitems = objent.GetList<PostsItem>("Posts");
var i = from item in evnitems
where item.PromoterId == SPContext.Current.Web.CurrentUser.ID
select item;

Entity Framework Optimistic Concurrency Exception not occuring

We have an ASP.Net MVC application that uses EF4 as its data access layer and we're seeing unexpected behaviour with regards to OptimisitcConcurrencyExceptions not being thrown when we think they should be.
We have simplified the problem down to the following code...
using System.Linq;
using Project.Model;
namespace OptimisticConcurrency
{
class Program
{
static void Main()
{
Contact firstContact = null;
using (var firstEntities = new ProjectEntities())
{
firstContact = (from c in firstEntities.Contacts
where c.LastName == "smith" select c).Single();
}
using (var secondEntities = new ProjectEntities())
{
var secondContact = (from c in secondEntities.Contacts
where c.LastName == "smith" select c).Single();
secondContact.Title = "a";
secondEntities.SaveChanges();
}
firstContact.Title = "b";
using (var thirdEntities = new ProjectEntities())
{
var thirdContact = (from c in thirdEntities.Contacts
where c.LastName == "smith" select c).Single();
thirdContact.Title = firstContact.Title;
//EXPLICITLY SET VERSION HERE
thirdContact.Version = firstContact.Version;
thirdEntities.SaveChanges();
}
}
}
}
This is a rather simple version of what happens in our MVC app, but the same problem occurs.
When we call SaveChanges on the thirdEntities, I expect the exception and nothing is being thrown.
Much more interestingly, when we attach the SQL Profiler, we see that the Version is being used in the where clause but it is thirdEntities Version value (the current one in the DB) being used, not the firstEntities values DESPITE it being explicitly set immediately before SaveChanges is called. SaveChanges is resetting the Version to be the retrieved value not the set value.
In the EDMX, the Version is set to have a StoreGeneratedPattern is set to Computed.
Anyone have any idea what is going on here?
This is a problem. Once the column is set to Computed you can't set its value in the application (you can but the value is not used).
Edit:
If you load entity from database it is by default tracked with the context. The context stores its original values. Original values are for example used for snapshot change tracking but they are also used as the only valid source of Computed properties. If you set Computed property in your entity the value is not used and original value is used insted. The workaround is to modify original value (before you modify anything else):
using (var context = new TestEntities())
{
var entityToUpdate = context.MyEntities.Single(e => e.Id == someId);
entityToUpdate.Timestamp = entity.Timestamp;
ObjectStateEntry entry = context.ObjectStateManager.GetObjectStateEntry(entityToUpdate);
entry.ApplyOriginalValues(entityToUpdate);
// set modified properties
context.SaveChanges();
}
Edit 2:
Btw. once you have both actually loaded timestamp and previously retrieved timestamp you can simply compare them in your application instead of doing it in the database.

Azure Table Storage, WCF Service and Enum

Here's my problem. A class which defines an order has a property called PaymentStatus, which is an enum defined like so:
public enum PaymentStatuses : int
{
OnDelivery = 1,
Paid = 2,
Processed = 3,
Cleared = 4
}
And later on, in the class itself, the property definition is very simple:
public PaymentStatuses? PaymentStatus { get; set; }
However, if I try to save an order to the Azure Table Storage, I get the following exception:
System.InvalidOperationException: The type Order+PaymentStatuses' has no settable properties.
At this point I thought using enum isn't possible, but a quick Google search returned this: http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/7eb1a2ca-6c1b-4440-b40e-012db98ccb0a
This page lists two answers, one of which seems to ignore the problems and suggests that using an enum in Azure Storage is fine.
Now, I don't NEED to store the enum in the Azure Table Storage as such, I could just as well store a corresponding int, however, I do need this property to be exposed in the WCF service.
I've tried making the property use get and set to return the enum from a stored integer, and remove this property from Azure by using the WritingEntity event on my DataContext, but I get that exception before the event for this entity is fired.
At this point, I'm at a loss, I don't know what else I can do to have this property in WCF as an enum, but have Azure store just the int.
Enum is not supported. Even though it is defined like an int, it is really not an integral type supported by Table Storage. Here is the list of types supported. An enum is just a string expression of an integral number with an object-oriented flavor.
You can store int in table storage and then convert it using Enum.Parse.
Here's a simple workaround:
public int MyEnumValue { get; set; } //for use by the Azure client libraries only
[IgnoreProperty] public MyEnum MyEnum
{
get { return (MyEnum) MyEnumValue; }
set { MyEnumValue = (int) value; }
}
It would have been nicer if a simple backing value could have been employed rather than an additional (public!) property - without the hassle of overriding ReadEntity/WriteEntity of course. I opened a user voice ticket that would facilitate that, so you might want to upvote it.
ya i was having this same problem
i changed my property which was earlier enum to int. now this int property parses the incoming int and saves it into a variale of the same enum type so now the code that was
public CompilerOutputTypes Type
{get; set;}
is chaged to
private CompilerOutputTypes type;
public int Type
{
get {return (int)type;}
set { type = (CompilerOutputTypes)value; }
}
Just suggestions...
I remember that in WCF you have to mark enums with special attributes: http://msdn.microsoft.com/en-us/library/aa347875.aspx
Also, when you declare PaymentStatuses? PaymentStatus, you are declaring Nullable<PaymentStatuses> PaymentStatus. The ? sintax is just syntactic sugar. Try to remove the ? and see what happen (you could add a PaymentStatuses.NoSet = 0 , because the default value for an Int32 is 0).
Good luck.
Parvs solution put me on the right track but I had some minor adjustments.
private string _EnumType;
private EnumType _Type;
//*********************************************
//*********************************************
public string EnumType
{
get { return _Type.ToString(); }
set
{
_EnumType = value;
try
{
_Type = (EnumType)Enum.Parse(typeof(EnumType), value);
}
catch (Exception)
{
_EnumType = "Undefined";
_Type = [mynamespace].EnumType.Undefined;
}
}
}
I have come across a similar problem and have implemented a generic object flattener/recomposer API that will flatten your complex entities into flat EntityProperty dictionaries and make them writeable to Table Storage, in the form of DynamicTableEntity.
Same API will then recompose the entire complex object back from the EntityProperty dictionary of the DynamicTableEntity.
This is relevant to your question because the ObjectFlattenerRecomposer API supports flattening property types that are normally not writeable to Azure Table Storage like Enum, TimeSpan, all Nullable types, ulong and uint by converting them into writeable EntityProperties.
The API also handles the conversion back to the original complex object from the flattened EntityProperty Dictionary. All that the client needs to do is to tell the API, I have this EntityProperty Dictionary that I just read from Azure Table (in the form of DynamicTableEntity.Properties), can you convert it to an object of this specific type. The API will recompose the full complex object with all of its properties including 'Enum' properties with their original correct values.
All of this flattening and recomposing of the original object is done transparently to the client (user of the API). Client does not need to provide any schema or any knowledge to the ObjectFlattenerRecomposer API about the complex object that it wants to write, it just passes the object to the API as 'object' to flatten it. When converting it back, the client only needs to provide the actual type of object it wants the flattened EntityProperty Dictionary to be converted to. The generic ConvertBack method of the API will simply recompose the original object of Type T and return it to the client.
See the usage example below. The objects do not need to implement any interface like 'ITableEntity' or inherit from a particular base class either. They do not need to provide a special set of constructors.
Blog: https://doguarslan.wordpress.com/2016/02/03/writing-complex-objects-to-azure-table-storage/
Nuget Package: https://www.nuget.org/packages/ObjectFlattenerRecomposer/
Usage:
//Flatten object (ie. of type Order) and convert it to EntityProperty Dictionary
Dictionary<string, EntityProperty> flattenedProperties = EntityPropertyConverter.Flatten(order);
// Create a DynamicTableEntity and set its PK and RK
DynamicTableEntity dynamicTableEntity = new DynamicTableEntity(partitionKey, rowKey);
dynamicTableEntity.Properties = flattenedProperties;
// Write the DynamicTableEntity to Azure Table Storage using client SDK
//Read the entity back from AzureTableStorage as DynamicTableEntity using the same PK and RK
DynamicTableEntity entity = [Read from Azure using the PK and RK];
//Convert the DynamicTableEntity back to original complex object.
Order order = EntityPropertyConverter.ConvertBack<Order>(entity.Properties);

Resources