When I run a Unit Test for my plugin I get the following Exception being Thrown:
Message: Test method Plugins.Tests.UnitTest1.TestUnitPlugin threw exception:
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
The following link will give you the stack trace:
Stacktrace
Even when I deploy & register my plugin to the online instance, I would get the same message!!
My Plugin code looks like this:
using System;
using System.Collections.Generic;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
/// <summary>
/// This plugin takes the data provided in the contract lines and makes Unit Orders.. Inside the unit orders, an Alter Unit Orders table is present.
/// The Alter Unit Orders table describes the daily order for each day in the contract's duration.
/// </summary>
namespace DCWIMS.Plugins
{
[CrmPluginRegistration(MessageNameEnum.Update,
"contract",
StageEnum.PreOperation,
ExecutionModeEnum.Synchronous,
"title",
"Post-Update Contract",
1000,
IsolationModeEnum.Sandbox,
Image1Name = "PreImage",
Image1Type = ImageTypeEnum.PreImage,
Image1Attributes = "title")]
public class UnitPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Extract the tracing service for use in debugging sandboxed plug-ins.
// Wil be registering this plugin, thus will need to add tracing service related code.
ITracingService tracing = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
//obtain execution context from service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
// The InputParameters colletion contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
//obtain the target entity from the input parameters.
Entity entity = (Entity)context.InputParameters["Target"];
//Obtain Target Entity Id
var targetId = entity.Id.ToString();
//verify that the target entity represents the the contract entity and is active
if (entity.LogicalName != "contract" && entity.GetAttributeValue<OptionSetValue>("statecode").Value != 0)
return;
//obtain the organization service for web service calls.
IOrganizationServiceFactory serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
try
{
//Get Contract StartDate
DateTime startDate = (DateTime)entity["activeon"];
//Get Contract EndDate
DateTime endDate = (DateTime)entity["expireson"];
//Get all weekdays in the contract duration
Eachday range = new Eachday();
var weekdays = range.WeekDay(startDate, endDate); //weekdays list
//Get Contract Number
string contractNumber = (string)entity["contractnumber"];
//Query and aggregate each Weekday's order for the 3 different meal times...
//AM SNACK
string unitsum_am = #" <fetch aggregate='true' distinct='false' >
<entity name='contract' >
<link-entity name='contractdetail' from = 'contractid' to = 'contractid' >
<attribute name='new_mondayunits' alias='new_mondayunits_amsum' aggregate='sum' />
<attribute name='new_tuesdayunits' alias='new_tuesdayunits_amsum' aggregate='sum' />
<attribute name='new_unitswednesday' alias='new_unitswednesday_amsum' aggregate='sum' />
<attribute name='new_unitsthursday' alias='new_unitsthursday_amsum' aggregate='sum' />
<attribute name='new_unitsfriday' alias='new_unitsfriday_amsum' aggregate='sum' />
<filter type='and' >
<condition value='100000001' attribute='new_servingtime' operator= 'eq' />
<condition value='0' attribute='statecode' operator= 'eq' />
<condition value='" + targetId + #"' attribute='contractid' operator= 'eq' />
</filter >
</link-entity>
</entity >
</fetch>";
EntityCollection unitsum_am_result =
service.RetrieveMultiple(new FetchExpression(unitsum_am));
var am_list = new List<int>();
foreach(var unit in unitsum_am_result.Entities)
{
var mondaysum = ((int)((AliasedValue)unit["new_mondayunits_amsum"]).Value);
am_list.Add(mondaysum);
var tuesdaysum = ((int)((AliasedValue)unit["new_tuesdayunits_amsum"]).Value);
am_list.Add(tuesdaysum);
var wednesdaysum= ((int)((AliasedValue)unit["new_unitswednesday_amsum"]).Value);
am_list.Add(wednesdaysum);
var thursdaysum= ((int)((AliasedValue)unit["new_unitsthursday_amsum"]).Value);
am_list.Add(thursdaysum);
var fridaysum= ((int)((AliasedValue)unit["new_unitsfriday_amsum"]).Value);
am_list.Add(fridaysum);
}
//LUNCH
string unitsum_lunch = #" <fetch aggregate='true' distinct='false' >
<entity name='contract' >
<link-entity name='contractdetail' from = 'contractid' to = 'contractid' >
<attribute name='new_mondayunits' alias='new_mondayunits_lunchsum' aggregate='sum' />
<attribute name='new_tuesdayunits' alias='new_tuesdayunits_lunchsum' aggregate='sum' />
<attribute name='new_unitswednesday' alias='new_unitswednesday_lunchsum' aggregate='sum' />
<attribute name='new_unitsthursday' alias='new_unitsthursday_lunchsum' aggregate='sum' />
<attribute name='new_unitsfriday' alias='new_unitsfriday_lunchsum' aggregate='sum' />
<filter type='and' >
<condition value='100000002' attribute='new_servingtime' operator= 'eq' />
<condition value='0' attribute='statecode' operator= 'eq' />
<condition value='" + targetId + #"' attribute='contractid' operator= 'eq' />
</filter >
</link-entity>
</entity >
</fetch>";
EntityCollection unitsum_lunch_result =
service.RetrieveMultiple(new FetchExpression(unitsum_lunch));
var lunch_list = new List<int>();
foreach (var unit in unitsum_lunch_result.Entities)
{
var mondaysum = ((int)((AliasedValue)unit["new_mondayunits_lunchsum"]).Value);
lunch_list.Add(mondaysum);
var tuesdaysum = ((int)((AliasedValue)unit["new_tuesdayunits_lunchsum"]).Value);
lunch_list.Add(tuesdaysum);
var wednesdaysum = ((int)((AliasedValue)unit["new_unitswednesday_lunchsum"]).Value);
lunch_list.Add(wednesdaysum);
var thursdaysum = ((int)((AliasedValue)unit["new_unitsthursday_lunchsum"]).Value);
lunch_list.Add(thursdaysum);
var fridaysum = ((int)((AliasedValue)unit["new_unitsfriday_lunchsum"]).Value);
lunch_list.Add(fridaysum);
}
//PM SNACK
string unitsum_pm = #" <fetch aggregate='true' distinct='false' >
<entity name='contract' >
<link-entity name='contractdetail' from = 'contractid' to = 'contractid' >
<attribute name='new_mondayunits' alias='new_mondayunits_pmsum' aggregate='sum' />
<attribute name='new_tuesdayunits' alias='new_tuesdayunits_pmsum' aggregate='sum' />
<attribute name='new_unitswednesday' alias='new_unitswednesday_pmsum' aggregate='sum' />
<attribute name='new_unitsthursday' alias='new_unitsthursday_pmsum' aggregate='sum' />
<attribute name='new_unitsfriday' alias='new_unitsfriday_pmsum' aggregate='sum' />
<filter type='and' >
<condition value='100000003' attribute='new_servingtime' operator= 'eq' />
<condition value='0' attribute='statecode' operator= 'eq' />
<condition value='" + targetId + #"' attribute='contractid' operator= 'eq' />
</filter >
</link-entity>
</entity >
</fetch>";
EntityCollection unitsum_pm_result =
service.RetrieveMultiple(new FetchExpression(unitsum_pm));
var pm_list = new List<int>();
foreach (var unit in unitsum_pm_result.Entities)
{
var mondaysum = ((int)((AliasedValue)unit["new_mondayunits_pmsum"]).Value);
pm_list.Add(mondaysum);
var tuesdaysum = ((int)((AliasedValue)unit["new_tuesdayunits_pmsum"]).Value);
pm_list.Add(tuesdaysum);
var wednesdaysum = ((int)((AliasedValue)unit["new_unitswednesday_pmsum"]).Value);
pm_list.Add(wednesdaysum);
var thursdaysum = ((int)((AliasedValue)unit["new_unitsthursday_pmsum"]).Value);
pm_list.Add(thursdaysum);
var fridaysum = ((int)((AliasedValue)unit["new_unitsfriday_pmsum"]).Value);
pm_list.Add(fridaysum);
}
foreach(var day in weekdays)
{
var alterunit = new Entity("new_alterunitorder");
alterunit.Attributes.Add("new_orderdate", DateTime.Parse(day));
switch (day.Split(',')[0])
{
case "Monday":
alterunit.Attributes.Add("new_amsnack", am_list[0]);
alterunit.Attributes.Add("new_lunch", lunch_list[0]);
alterunit.Attributes.Add("new_pmsnack", pm_list[0]);
break;
case "Tuesday":
alterunit.Attributes.Add("new_amsnack", am_list[1]);
alterunit.Attributes.Add("new_lunch", lunch_list[1]);
alterunit.Attributes.Add("new_pmsnack", pm_list[1]);
break;
case "Wednesday":
alterunit.Attributes.Add("new_amsnack", am_list[2]);
alterunit.Attributes.Add("new_lunch", lunch_list[2]);
alterunit.Attributes.Add("new_pmsnack", pm_list[2]);
break;
case "Thursday":
alterunit.Attributes.Add("new_amsnack", am_list[3]);
alterunit.Attributes.Add("new_lunch", lunch_list[3]);
alterunit.Attributes.Add("new_pmsnack", pm_list[3]);
break;
case "Friday":
alterunit.Attributes.Add("new_amsnack", am_list[4]);
alterunit.Attributes.Add("new_lunch", lunch_list[4]);
alterunit.Attributes.Add("new_pmsnack", pm_list[4]);
break;
default:
Console.WriteLine($"An unexpected value ({day.Split(',')})");
break;
}
alterunit.Attributes.Add("new_name", contractNumber); //set the record name
//set the unit order record relation
alterunit.Attributes["new_orderlineid"] =
new EntityReference("new_alterunitorder", unitOrderId);
service.Create(alterunit);
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occured.. Phil is responsible.", ex);
}
catch (Exception ex)
{
tracing.Trace("An Error Occured: {0}", ex.ToString());
throw;
}
}
}
}
}
Here is the code for Eachday:
using System;
using System.Collections.Generic;
namespace DCWIMS.Plugins
{
public class Eachday
{
public List<string> WeekDay(DateTime from, DateTime thru)
{
List<string> days_list = new List<string>();
for (var day = from.Date; day.Date <= thru.Date; day = day.AddDays(1))
{
days_list.Add(day.ToLongDateString());
if (day.DayOfWeek == DayOfWeek.Sunday || day.DayOfWeek == DayOfWeek.Saturday)
days_list.Remove(day.ToLongDateString());
}
return days_list;
}
}
}
My unit test looks like this:
using DCWIMS.Plugins;
using Microsoft.Crm.Sdk.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Xrm.Sdk;
namespace Plugins.Tests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
[TestCategory("Unit Test")]
public void TestUnitPlugin()
{
using (var pipline = new PluginPipeline(FakeMessageNames.Update, FakeStages.PreOperation, new Entity("contract")))
{
var plugin = new UnitPlugin();
pipline.Execute(plugin);
}
}
}
}
Even when I registered the plugin on the actual CRM instance I got this error message:
Here is the log file retrieved from CRM Online!
Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: Unexpected exception from plug-in (Execute): DCWIMS.Plugins.UnitPlugin: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.Detail:
<OrganizationServiceFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
<ActivityId>4025e0f8-eed5-4b7f-a3b1-52a9f2a6f2cc</ActivityId>
<ErrorCode>-2147220956</ErrorCode>
<ErrorDetails xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<Message>Unexpected exception from plug-in (Execute): DCWIMS.Plugins.UnitPlugin: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.</Message>
<Timestamp>2018-07-20T17:47:36.4061434Z</Timestamp>
<ExceptionRetriable>false</ExceptionRetriable>
<ExceptionSource i:nil="true" />
<InnerFault i:nil="true" />
<OriginalException i:nil="true" />
<TraceText>
[Plugins: DCWIMS.Plugins.UnitPlugin]
[dbb33fa1-448c-e811-815c-480fcff4b5b1: Pre-Create Contract]
An Error Occured: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at Microsoft.Xrm.Sdk.AttributeCollection.get_Item(String attributeName)
at DCWIMS.Plugins.UnitPlugin.Execute(IServiceProvider serviceProvider)
</TraceText>
</OrganizationServiceFault
>
Unit testing ain't my forte. But I will try to guide you.
First, my opinion on unit testing. I don't value it much in Dynamics because it's an environment that is hard to control. You can test that your business logic is well implemented in the plugin but a javascript, a business rule, a workflow or an action can derail your logic. Your plugin can say blue but an async workflow change it to red right after.
Instead, I prefer UI testing. It will test the process from A to Z and force the execution of all the components mentioned above. Here's a nice framework I recommend: https://github.com/Microsoft/EasyRepro
That being said. To solve your problem you also need to mock the Organization Service and return fake data. By that, I mean this line:
EntityCollection unitsum_am_result = service.RetrieveMultiple(new FetchExpression(unitsum_am));
Sadly, even if you mock, you can't really parse the fetchXml and validate it.
Then, after returning the fake data you should assert that this line, create an entity with the right sums:
service.Create(alterunit);
I created a custom GEOIP provider but the code I have always returns unknown country in Experience Analytics.
Below are my codes:
public class GeoLiteProvider : LookupProviderBase
{
public override WhoIsInformation GetInformationByIp(string ip)
{
const string ModuleName = "Utilities.GeoIP";
string vLogging = Settings.GetSetting(ModuleName + ".VerboseLogging", "false");
bool vLoggingResult = false;
bool verboseLogging = bool.TryParse(vLogging, out vLoggingResult);
if (!vLoggingResult)
{
verboseLogging = false;
}
WebRequest rssReq = WebRequest.Create("http://www.telize.com/geoip/" + ip);
WebProxy px = new WebProxy("http://www.telize.com/geoip/" + ip, true);
rssReq.Proxy = px;
rssReq.Timeout = 2000;
WhoIsInformation information = new WhoIsInformation();
try
{
WebResponse rep = rssReq.GetResponse();
StreamReader content = new StreamReader(rep.GetResponseStream());
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
System.Collections.Generic.Dictionary<string, object> jsonObject = (System.Collections.Generic.Dictionary<string, object>)serializer.DeserializeObject(content.ReadToEnd());
if (jsonObject != null)
{
information.Country = jsonObject["country"] != null ? jsonObject["country"].ToString() : string.Empty;
if (verboseLogging)
{
Log.Info(ModuleName + ": information.Country = " + information.Country, this);
}
information.Region = jsonObject["region"] != null ? jsonObject["region"].ToString() : string.Empty;
if (verboseLogging)
{
Log.Info(ModuleName + ": information.Region = " + information.Region, this);
}
information.City = jsonObject["city"] != null ? jsonObject["city"].ToString() : string.Empty;
if (verboseLogging)
{
Log.Info(ModuleName + ": information.City = " + information.City, this);
}
information.PostalCode = string.Empty;
if (verboseLogging)
{
Log.Info(ModuleName + ": information.PostalCode = " + information.PostalCode, this);
}
information.Latitude = double.Parse(jsonObject["latitude"].ToString());
if (verboseLogging)
{
Log.Info(ModuleName + ": information.Latitude = " + information.Latitude, this);
}
information.Longitude = double.Parse(jsonObject["longitude"].ToString());
if (verboseLogging)
{
Log.Info(ModuleName + ": information.Longitude = " + ((information.Longitude == 0) ? string.Empty : information.Longitude.ToString()), this);
}
information.MetroCode = string.Empty;
if (verboseLogging)
{
Log.Info(ModuleName + ": information.MetroCode = " + information.MetroCode, this);
}
information.AreaCode = jsonObject["area_code"] != null ? jsonObject["area_code"].ToString() : string.Empty;
if (verboseLogging)
{
Log.Info(ModuleName + ": information.AreaCode = " + information.AreaCode, this);
}
}
else
{
Log.Info(ModuleName + ": IP location cannot be determined. IP Address: " + ip, this);
information.BusinessName = Settings.GetSetting(ModuleName + ".NoLocationText", "Not Available");
}
if (verboseLogging)
{
Log.Info(ModuleName + ": IP Lookup Complete", this);
}
}
catch(Exception ex)
{
Log.Error(ModuleName + ": Exception occurred. Exception: " + ex.Message, this);
}
return information;
}}
Config Patch:
<lookupManager>
<patch:attribute name="defaultProvider">geoLite</patch:attribute>
<providers>
<add patch:after="*[#type='Sitecore.Analytics.Lookups.MaxMindProvider,Sitecore.Analytics']" name="geoLite" type="Core.Utilities.LookupProvider.GeoLiteProvider, Core.Utilities" />
</providers>
</lookupManager>
I also created a pipeline to override the IP address so I could verify it in my local machine but still fails.
public class OverrideIPAddress
{
public void Process(StartTrackingArgs args)
{
Tracker.Current.Interaction.Ip = System.Net.IPAddress.Parse("1.68.0.0").GetAddressBytes();
}
}
Sitecore.Analytics.Tracking.Config:
<startTracking>
<processor type="Sitecore.Analytics.Pipelines.StartTracking.RaiseStartTracking, Sitecore.Analytics" />
<processor type="Sitecore.Analytics.Pipelines.StartTracking.InitializeTracker, Sitecore.Analytics" />
<processor type="Utilities.GEOIP.OverrideIPAddress, Core.Utilities" />
<processor type="Sitecore.Analytics.Pipelines.StartTracking.TrackerInitialized, Sitecore.Analytics" />
<processor type="Sitecore.Analytics.Pipelines.StartTracking.UpdateGeoIpData, Sitecore.Analytics" />
<processor type="Sitecore.Analytics.Pipelines.StartTracking.ProcessQueryStringCampaign, Sitecore.Analytics" />
<processor type="Sitecore.Analytics.Pipelines.StartTracking.ProcessQueryStringPageEvent, Sitecore.Analytics" />
<processor type="Sitecore.Analytics.Pipelines.StartTracking.ProcessQueryStringTriggers, Sitecore.Analytics">
<triggers hint="raw:AddTrigger">
<trigger querystring="sc_rss" eventname="RSS"/>
</triggers>
</processor>
<processor type="Sitecore.Analytics.Pipelines.StartTracking.ProcessItem, Sitecore.Analytics"/>
</startTracking>
Here is what I get when I debugg in my local machine:
Additionally, I added this in my BaseLayouts.
#Html.Sitecore().VisitorIdentification()
Let me know what I've missing.
I'm fairly certain the Countries need to be country codes that line up with the items in the path /sitecore/system/Settings/Analytics/Lookups/Countries
You'll notice that those items all have a "Country code" field and this is the value you generally find in the analytics data.
Judging by what you posted above I am guessing that your service returns the full name? I would suggest setting up a static dictionary in the Init pipeline that reads all the CountryItem values keyed on Country name and you can use that to encode the values from your service. There may already be a dictionary like this in Sitecore somewhere but with only a cursory glance I wasn't able to locate one.
(The original post is here:https://social.technet.microsoft.com/Forums/sharepoint/en-US/6b02dfe8-5594-4d25-991a-51ac9a0528b7/sharepoint-2013-fba-errorcould-not-retrieve-the-iis-settingsparameter-name-context?forum=sharepointadminprevious)
I am trying to use windows live to login sharepoint 2013. From some posts, I could get windows live token(aouth 2.0) and windows live user profile. It will redirect to my sharepoint site.
I follow some articles to develop my custom login page:
also I defined my membership provider and role provider
public class LiveMembershipProvider : MembershipProvider
{
private MembershipUserCollection employees;
private void generateUsers()
{
//Mock Data
employees = new MembershipUserCollection();
employees.Add(new MembershipUser(this.Name, "Jack Chen", "JackChen", "Jack#Chen.com", "What your Name?", "I am Jack", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));
employees.Add(new MembershipUser(this.Name, "Bruce Li", "BruceLi", "BruceLi#Li.com", "How are u?", "How old are u", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));
employees.Add(new MembershipUser(this.Name, "Eyes Wang", "EyesWang", "EyesWang#Mintcode.com", "What the hell?", "what the fuck", true, false, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today, DateTime.Today));
}
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
{
if (employees == null) generateUsers();
MembershipUserCollection returnFoundUsers = new MembershipUserCollection();
(employees.Cast<MembershipUser>().
Where(membershipUser => membershipUser.UserName.ToLowerInvariant().Contains(usernameToMatch.ToLowerInvariant())))
.ToList().ForEach(returnFoundUsers.Add);
totalRecords = returnFoundUsers.Count;
return returnFoundUsers;
}
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
if (employees == null) generateUsers();
totalRecords = employees.Count;
return employees;
}
public override MembershipUser GetUser(string username, bool userIsOnline)
{
if (employees == null) generateUsers();
IEnumerable<MembershipUser> usersFound = employees.Cast<MembershipUser>().Where(membershipUser => membershipUser.UserName == username);
return usersFound.FirstOrDefault();
}
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
if (employees == null) generateUsers();
IEnumerable<MembershipUser> usersFound = employees.Cast<MembershipUser>().Where(membershipUser => membershipUser.ProviderUserKey.ToString() == providerUserKey.ToString());
return usersFound.FirstOrDefault();
}
public override string GetUserNameByEmail(string email)
{
if (employees == null) generateUsers();
IEnumerable<MembershipUser> usersFound = employees.Cast<MembershipUser>().Where(membershipUser => membershipUser.Email.ToLowerInvariant() == email.ToLowerInvariant());
MembershipUser user = usersFound.FirstOrDefault();
if (user != null)
return user.UserName;
else
return null;
}
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
if (employees == null) generateUsers();
MembershipUserCollection returnFoundUsers = new MembershipUserCollection();
(employees.Cast<MembershipUser>().
Where(membershipUser => membershipUser.Email.ToLowerInvariant().Contains(emailToMatch.ToLowerInvariant())))
.ToList().ForEach(returnFoundUsers.Add);
totalRecords = returnFoundUsers.Count;
return returnFoundUsers;
}
public override bool ValidateUser(string username, string password)
{
//return true;
if (employees == null) generateUsers();
IEnumerable<MembershipUser> usersFound = employees.Cast<MembershipUser>().Where(membershipUser => membershipUser.UserName == username);
MembershipUser user = usersFound.FirstOrDefault();
if (user != null)
{
if (string.IsNullOrEmpty(password))
{
return false;
}
else
{
return true;
}
}
else
return false;
}
}
public class LiveRoleProvider : RoleProvider
{
public override string ApplicationName { get; set; }
private string[] m_AllRoles = { "Vendor" };
private string[,] m_RolesForUser = new string[,] {
{"Eyes Wang", "Vendor"},
{"Bruce Li","Vendor"},
{"Jack Chen","Vendor"}
};
public override string[] GetAllRoles()
{
return m_AllRoles;
}
public override string[] GetRolesForUser(string username)
{
List<string> roles = new List<string>();
for (int i = 0; i <= m_RolesForUser.GetUpperBound(0); i++)
{
if (m_RolesForUser[i, 0] == username)
{
roles = m_RolesForUser[i, 1].Split(',').ToList<string>();
}
}
return roles.ToArray();
}
public override string[] GetUsersInRole(string rolename)
{
List<string> users = new List<string>();
for (int i = 0; i <= m_RolesForUser.GetUpperBound(0); i++)
{
List<string> userRoles = m_RolesForUser[i, 1].Split(',').ToList<string>();
if (userRoles.Where(userRole => userRole == rolename).Count() > 0)
{
users.Add(m_RolesForUser[i, 0]);
}
}
return users.ToArray();
}
public override bool IsUserInRole(string username, string rolename)
{
List<string> usersForRole = GetUsersInRole(rolename).ToList();
if (usersForRole.Where(userName => userName == username).Count() > 0)
{
return true;
}
else
{
return false;
}
}
public override bool RoleExists(string rolename)
{
bool roleExsists = m_AllRoles.ToList().Where(roleName => roleName == rolename).Count() > 0;
return roleExsists;
}
public override string[] FindUsersInRole(string rolename, string usernameToMatch)
{
List<string> users = GetUsersInRole(rolename).ToList<string>();
List<string> foundUsers = users.Where(userName => userName.ToLowerInvariant().Contains(usernameToMatch.ToLowerInvariant())).ToList<string>();
return foundUsers.ToArray();
}
}
In the Central Application web.config
I add
<roleManager>
<providers>
<add name="LiveRoleProvider" type="SPLiveWebForm.LiveRoleProvider,SPLiveWebForm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=34a64026791bbfa4" />
</providers>
</roleManager>
<membership>
<providers>
<add name="LiveMembershipProvider" type="SPLiveWebForm.LiveMembershipProvider,SPLiveWebForm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=34a64026791bbfa4" />
</providers>
</membership>
<PeoplePickerWildcards>
<clear />
<add key="AspNetSqlMembershipProvider" value="%" />
<add key="LiveMembershipProvider" value="%" />
</PeoplePickerWildcards>
In the WA web.config
<membership defaultProvider="i">
<providers>
<add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="LiveMembershipProvider" type="SPLiveWebForm.LiveMembershipProvider,SPLiveWebForm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=34a64026791bbfa4" />
</providers>
</membership>
<roleManager defaultProvider="c" enabled="true" cacheRolesInCookie="false">
<providers>
<add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="LiveRoleProvider" type="SPLiveWebForm.LiveRoleProvider,SPLiveWebForm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=34a64026791bbfa4" />
</providers>
</roleManager>
<PeoplePickerWildcards>
<clear />
<add key="AspNetSqlMembershipProvider" value="%" />
<add key="LiveMembershipProvider" value="%" />
</PeoplePickerWildcards>
In the STS web.config
<system.web>
<membership defaultProvider="i">
<providers>
<add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="LiveMembershipProvider" type="SPLiveWebForm.LiveMembershipProvider,SPLiveWebForm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=34a64026791bbfa4" />
</providers>
</membership>
<roleManager defaultProvider="c" enabled="true" cacheRolesInCookie="false">
<providers>
<add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider, Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<add name="LiveRoleProvider" type="SPLiveWebForm.LiveRoleProvider,SPLiveWebForm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=34a64026791bbfa4" />
</providers>
</roleManager>
</system.web>
I could successfully login to share point by using the default login page (http://www.akmii.com/_forms/default.aspx)
But using my customize page (when I get windows live user profile then try to use the follow method to login sharepoint)
private void SPUserLogin(string usrName)
{
string userProviderName = string.Empty;
string roleProviderName = string.Empty;
foreach (MembershipProvider p in Membership.Providers)
{
if (p.GetType().Equals(typeof(LiveMembershipProvider)))
{
userProviderName = p.Name;
break;
}
}
foreach (RoleProvider rp in System.Web.Security.Roles.Providers)
{
if (rp.GetType().Equals(typeof(LiveRoleProvider)))
{
roleProviderName = rp.Name;
break;
}
}
SecurityToken tk = null;
try
{
tk = SPSecurityContext.SecurityTokenForFormsAuthentication(
new Uri(SPContext.Current.Web.Url), userProviderName, roleProviderName,
"Jack Chen", "123", SPFormsAuthenticationOption.PersistentSignInRequest);
}
catch (Exception e)
{
Response.Write(e.Message);
}
if (tk != null)
{
//try setting the authentication cookie
SPFederationAuthenticationModule fam = SPFederationAuthenticationModule.Current;
fam.SetPrincipalAndWriteSessionToken(tk);
//look for the Source query string parameter and use that as the redirection
//string src = Request.QueryString["Source"];
string src = "http://www.akmii.com/_layouts/15/start.aspx#/SitePages/Home.aspx";
if (!string.IsNullOrEmpty(src))
Response.Redirect(src);
}
else
{
}
}
}
There is an exception throwing out in the catch section:
Could not retrieve the IIS Settings.Parameter name: context
The error stack as follows:
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.ReadResponse(Message response)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.Issue(RequestSecurityToken rst, RequestSecurityTokenResponse& rstr)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.Issue(RequestSecurityToken rst)
at Microsoft.SharePoint.SPSecurityContext.SecurityTokenForContext(Uri context, Boolean bearerToken, SecurityToken onBehalfOf, SecurityToken actAs, SecurityToken delegateTo, SPRequestSecurityTokenProperties properties)
at Microsoft.SharePoint.SPSecurityContext.SecurityTokenForFormsAuthentication(Uri context, String membershipProviderName, String roleProviderName, String username, String password, SPFormsAuthenticationOption options)
at SPLiveWebForm.Layouts.SPLiveWebForm.Login.SPUserLogin(String usrName)
If I use
bool status = SPClaimsUtility.AuthenticateFormsUser(
new Uri(SPContext.Current.Web.Url),
usrName,
"123");
The same exception throw out.
at Microsoft.SharePoint.IdentityModel.SPFormsOriginalIssuerBuilder.GetFormsAuthenticationProviderFromContext(Uri context)
at Microsoft.SharePoint.IdentityModel.SPFormsOriginalIssuerBuilder.ValidateFormsAuthProviderNames(Uri context, String membershipProvider, String roleProvider)
at Microsoft.SharePoint.IdentityModel.SPFormsOriginalIssuerBuilder.SetProviderNames()
at Microsoft.SharePoint.IdentityModel.SPSecurityTokenService.SPRequestInfo.InitializeForForms(SPRequestSecurityToken request)
at Microsoft.SharePoint.IdentityModel.SPSecurityTokenService.GetTokenLifetime(Lifetime requestLifetime)
at Microsoft.IdentityModel.SecurityTokenService.SecurityTokenService.Issue(IClaimsPrincipal principal, RequestSecurityToken request)
at Microsoft.SharePoint.IdentityModel.SPSecurityTokenService.Issue(IClaimsPrincipal principal, RequestSecurityToken request)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract.DispatchRequest(DispatchContext dispatchContext)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract.ProcessCore(Message requestMessage, WSTrustRequestSerializer requestSerializer, WSTrustResponseSerializer responseSerializer, String requestAction, String responseAction, String trustNamespace)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract.ProcessTrust13Issue(Message message)
at SyncInvokeProcessTrust13Issue(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
I spend whole day to dig this issue but failed.
Is there any solution to resolve this?
Many Thanks!
Vincent
I had the same problem.
In my case I had to go to the Central Administartion => System Settings => Configure alternate access mappings.
Click on "Edit Public URLs", select Your app in "Alternate access mappings collection" and then fill up "Internet" textbox.
I am not sure what value is correct, but I filled it with my sharepoint URL with default (80) port.
Hope it help You.
I want to retrieve list of images from database that are stored in the form of bytes.I am able to return only single images bytes length.How can i send list of bytes .i am using below code please let me know
public List<Byte[]> GetAllProjectStandardIcons()
{
var qry = (from p in dbModel.tbl_STANDARDPROJECTICONS
select new
{
p.ProjectIcons
}).ToList();
//How to return list here from WCF web service
}
I have tried to create a service with an Image Service that returns images from the images stored in the same folder as the service. You can the streaming later if you want.
[ServiceContract]
public interface IImagesService
{
[OperationContract]
List<Byte[]> FetchImages();
}
public class ImagesService : IImagesService
{
List<string> images = new List<string>();
public ImagesService()
{
images.Add("Box.png");
images.Add("Clock.png");
}
public List<byte[]> FetchImages()
{
List<Byte[]> imagesInBytes = new List<byte[]>();
foreach (var image in images)
{
Image newImage = new Bitmap(image);
byte[] b = this.imageToByteArray(newImage);
imagesInBytes.Add(b);
}
return imagesInBytes;
}
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
}
Hosted the service on httpbinding
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="NewBehavior0">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="WCFImagesExample.ImagesService" behaviorConfiguration="NewBehavior0">
<endpoint address="Images" binding="basicHttpBinding" bindingConfiguration=""
contract="WCFImagesExample.IImagesService" />
<endpoint address="mex" binding="mexHttpBinding" bindingConfiguration=""
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:{portnumber}" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
Now you can create a client proxy and save the images back
static void Main(string[] args)
{
ImagesReference.IImagesService imagesService = new ImagesServiceClient();
byte[][] bytes = imagesService.FetchImages();
int i=0;
foreach (byte[] byteArray in bytes)
{
Image image = byteArrayToImage(byteArray);
image.Save(#"c:\Development\" + i + ".png");
i++;
}
}
public static Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
Highly like you want to return an image. No matter what you can have a look at the following:Large Data and Streaming
I have been trying to troubleshoot this error for a long time.
"An error occurred when verifying security for the message"
I did some research, people said this is because the time difference between the server and the client.
This anyone else have the same problem?
Below is the detail of my error
System.ServiceModel.FaultException was caught
Message=An error occurred when verifying security for the message.
Source=mscorlib
StackTrace:
Server stack trace:
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at WindowsFormsApplication1.CrmSdk.Discovery.IDiscoveryService.Execute(DiscoveryRequest request)
at WindowsFormsApplication1.CrmSdk.Discovery.DiscoveryServiceClient.Execute(DiscoveryRequest request) in WindowsFormsApplication1\Service References\CrmSdk.Discovery\Reference.cs:line 723
at WindowsFormsApplication1.Form1.DiscoverOrganizationUrl(String organizationName, String discoveryServiceUrl) in Form1.cs:line 110
InnerException:
Here is the code i used to access the hosted CRM online webservice
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Web;
//using System.ServiceModel;
//using System.ServiceModel.Description;
namespace WindowsFormsApplication1
{
using CrmSdk;
using CrmSdk.Discovery;
using System.Net;
using System.Globalization;
using LocalServices;
using System.ServiceModel;
using System.Web.Services.Protocols;
public partial class Form1 : Form
{
///hosted CRM online
private const string DiscoveryServiceUrl = "https://disco.crm.dynamics.com/XRMServices/2011/Discovery.svc";
private IOrganizationService _service;
private string fetchXML =
#"
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='account'>
<attribute name='name' />
<attribute name='address1_city' />
<attribute name='primarycontactid' />
<attribute name='telephone1' />
<attribute name='accountid' />
<order attribute='name' descending='false' />
<filter type='and'>
<condition attribute='ownerid' operator='eq-userid' />
<condition attribute='statecode' operator='eq' value='0' />
</filter>
<link-entity name='contact' from='contactid' to='primarycontactid' visible='false' link-type='outer' alias='accountprimarycontactidcontactcontactid'>
<attribute name='emailaddress1' />
</link-entity>
</entity>
</fetch>
";
public Form1()
{
InitializeComponent();
//GetDataFromCRM();
GetDataFromCRM2();
}
private void GetDataFromCRM2()
{
private string DiscoverOrganizationUrl(string organizationName, string discoveryServiceUrl)
{
using (CrmSdk.Discovery.DiscoveryServiceClient client = new CrmSdk.Discovery.DiscoveryServiceClient("CustomBinding_IDiscoveryService", discoveryServiceUrl))
{
//ApplyCredentials(client, credentials);
client.ClientCredentials.Windows.ClientCredential.UserName = UserName;
client.ClientCredentials.Windows.ClientCredential.Password = Password
client.ClientCredentials.Windows.ClientCredential.Domain = Domain
CrmSdk.Discovery.RetrieveOrganizationRequest request = new CrmSdk.Discovery.RetrieveOrganizationRequest()
{
UniqueName = organizationName
};
try
{
CrmSdk.Discovery.RetrieveOrganizationResponse response = (CrmSdk.Discovery.RetrieveOrganizationResponse)client.Execute(request);
foreach (KeyValuePair<CrmSdk.Discovery.EndpointType, string> endpoint in response.Detail.Endpoints)
{
if (CrmSdk.Discovery.EndpointType.OrganizationService == endpoint.Key)
{
Console.WriteLine("Organization Service URL: {0}", endpoint.Value);
return endpoint.Value;
}
}
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
"Organization {0} does not have an OrganizationService endpoint defined.", organizationName));
}
catch (FaultException e)
{
MessageBox.Show(e.Message);
throw;
}
catch (SoapHeaderException e)
{
MessageBox.Show(e.Message);
throw;
}
catch (SoapException e)
{
MessageBox.Show(e.Message);
throw;
}
return null;
}
}
//private static void ApplyCredentials<TChannel>(ClientBase<TChannel> client, ICredentials credentials)
// where TChannel : class
//{
// client.ClientCredentials.Windows.ClientCredential = credentials.Windows.ClientCredential;
//}
private void ExecuteFetch(string serviceUrl)
{
using (OrganizationServiceClient client = new OrganizationServiceClient("CustomBinding_IOrganizationService", new EndpointAddress(serviceUrl)))
{
client.ClientCredentials.Windows.ClientCredential.UserName = UserName;
client.ClientCredentials.Windows.ClientCredential.Password = Password;
client.ClientCredentials.Windows.ClientCredential.Domain = Domain;
_service = (IOrganizationService)client;
FetchExpression expression = new FetchExpression();
expression.Query =
#"
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='account'>
<attribute name='name' />
<attribute name='address1_city' />
<attribute name='primarycontactid' />
<attribute name='telephone1' />
<attribute name='accountid' />
<order attribute='name' descending='false' />
<filter type='and'>
<condition attribute='ownerid' operator='eq-userid' />
<condition attribute='statecode' operator='eq' value='0' />
</filter>
<link-entity name='contact' from='contactid' to='primarycontactid' visible='false' link-type='outer' alias='accountprimarycontactidcontactcontactid'>
<attribute name='emailaddress1' />
</link-entity>
</entity>
</fetch>
";
EntityCollection result = _service.RetrieveMultiple(expression);
DataTable temp = ConvertEntityToTable(result);
}
}
/// Convert Entity To datatable
private DataTable ConvertEntityToTable(EntityCollection result)
{
DataTable dt = new DataTable();
int rowCount = result.Entities.Count();
try
{
for (int i = 0; i < rowCount; i++)
{
DataRow dr = dt.NewRow();
Entity currentEntity = (Entity)result.Entities[i];
var keys = currentEntity.Attributes.Count();
for (int j = 0; j < keys; j++)
{
string columName = currentEntity.Attributes[j].Key;
string value = currentEntity.Attributes[j].Value.ToString();
if (dt.Columns.IndexOf(columName) == -1)
dt.Columns.Add(columName, Type.GetType("Sysem.String"));
dr[columName] = value;
}
dt.Rows.Add(dr);
}
return dt;
}
catch (Exception exp)
{
throw;
}
}
}
}
app.config
<bindings>
<customBinding>
<binding name="CustomBinding_IDiscoveryService">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Default" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpsTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" requireClientCertificate="false"
/>
</binding>
It throw the error at FaultException
Thanks for all the help
The general consensus appears to be that besides the actual time, the timezone and daylight savings time settings appear to be the cause of this error. The client and server need to be in sync with each other.