Exception in Entity Framework: Error 0194: All artifacts loaded - .net-4.0

This is a c#/asp.net project. The full error message I get is:Error 0194: All artifacts loaded into the item collection must have the same version. Multiple versions were encountered.
This project was started as a 3.5 and upgraded to 4.0. When I try to test any of the methods I get the error that I posted in the subject line. I am going to include the actual lines that it throws the exception on. If there is anything in people need to see to try to help let me know and I post it as well. Any help will be appreciated, I am having no luck with this.
/// <summary>
/// Initializes a new SFBExternalPaymentsEntities object using the connection string found in the 'SFBExternalPaymentsEntities' section of the application configuration file.
/// </summary>
public SFBExternalPaymentsEntities() : base("name=SFBExternalPaymentsEntities", "SFBExternalPaymentsEntities")
{
this.ContextOptions.LazyLoadingEnabled = false;
OnContextCreated();
}
/// <summary>
/// Initialize a new SFBExternalPaymentsEntities object.
/// </summary>
public SFBExternalPaymentsEntities(string connectionString) : base(connectionString, "SFBExternalPaymentsEntities")
{
this.ContextOptions.LazyLoadingEnabled = false;
OnContextCreated();
}
/// <summary>
/// Initialize a new SFBExternalPaymentsEntities object.
/// </summary>
public SFBExternalPaymentsEntities(EntityConnection connection) : base(connection, "SFBExternalPaymentsEntities")
{
this.ContextOptions.LazyLoadingEnabled = false;
OnContextCreated();
}
#endregion
Added a method calling the constructor.
public static CreditCardResponse AuthCapture(CreditCard newCC)
{
ACHResponse validateResponse = CreditCard.Validate(newCC);
if (validateResponse.Status == "Accepted")
{
Profile currentProfile = new Profile();
currentProfile = ProfilesGateWay.GetByID(newCC.ProfileID);
CreditCardTransaction newCCTransaction = CreateCreditCardTransaction(newCC, currentProfile);
ServiceClient client = new ServiceClient();
CreditCardTransactionResponse cctResponse = client.CreditCardAuthorizeAndCapture(newCCTransaction);
client.Close();
CreditCardResponse ccResponse = CreateCCResponse(cctResponse);
if (ccResponse.ResponseCode == 1)
{
int authAVS = ConvertAVStoInt(ccResponse.AVSResponse);
int appAVS = ConvertAVStoInt(newCC.AVLevel);
bool isAVSPass = CompareAVS(authAVS, appAVS);
if (isAVSPass == false)
{
ccResponse.ResponseCode = 0;
ccResponse.ResponseReasonCode = 99;
ccResponse.ResponseText = "Did not meet your AVS requirements";
return ccResponse;
}
else
{
int newCCID = CreateCreditCardRecord(newCC, currentProfile, cctResponse, "Captured", "Auth_Capture");
CreditCardRecord updateCC = CreditCardRecordsGateWay.GetByID(newCCID);
updateCC.CaptureOn = DateTime.Now;
CreditCardRecordsGateWay.Update(updateCC);
return ccResponse;
}
}
else
{
return ccResponse;
}
}
CreditCardResponse newCCResponse = new CreditCardResponse();
newCCResponse.ResponseCode = 0;
newCCResponse.AchResponse = validateResponse;
return newCCResponse;
}
public static CreditCardResponse PriorAuthCapture(CreditCard newCC)
{
CreditCardRecord ccRecord = CreditCardRecordsGateWay.GetByCCGateWayID(newCC.CreditCardTransactionID);
ServiceClient client = new ServiceClient();
CreditCardTransaction ccTransaction = client.CreditCardGetTransactionById(ccRecord.CCGatewayID);
CreditCardTransactionResponse cctResponse = client.CreditCardPriorAuthorizationCapture(ccTransaction);
if (cctResponse.ResponseCode == 1)
{
ccRecord.Status = "Captured";
ccRecord.CaptureOn = DateTime.Now;
}
CreditCardResponse ccResponse = CreateCCResponse(cctResponse);
return ccResponse;
}
protected static int CreateCreditCardRecord(CreditCard newCC, Profile currentProfile, CreditCardTransactionResponse cctResponse, string status, string transactionType)
{
CreditCardRecord newCCRecord = new CreditCardRecord();
newCCRecord.Address = newCC.Address;
newCCRecord.AddressVerificationLevel = newCC.AVLevel;
newCCRecord.Amount = newCC.Amount;
newCCRecord.CardCode = newCC.CardCode;
newCCRecord.CardNumber = newCC.CardNumber;
newCCRecord.CCGatewayID = cctResponse.CreditCardTransactionID;
newCCRecord.City = newCC.City;
newCCRecord.CompanyName = newCC.CompanyName;
newCCRecord.CreateBy = currentProfile.ACHCompanyName;
newCCRecord.CreateOn = DateTime.Now;
newCCRecord.Description = newCC.Description;
newCCRecord.Expiration = newCC.Expiration;
newCCRecord.FirstName = newCC.FirstName;
newCCRecord.LastName = newCC.LastName;
newCCRecord.Profile.ProfileID = currentProfile.ProfileID;
newCCRecord.State = newCC.State;
newCCRecord.Status = status;
newCCRecord.TransactionType = transactionType;
newCCRecord.Zip = newCC.Zip;
return CreditCardRecordsGateWay.Insert(newCCRecord);
}

You have just posted the constructors to your SFBExternalPaymentsEntities class, but you seem to say that you get an exception when you call a method that returns a collection of entities, which makes send with the exception message you are getting. The chances are the problem lies within the method you are calling, or in the code calling it rather than in the constructor code you have posted. Can you post some more relevent code or explain how the code you have posted relates to the exception.

I encountered the same problem when i updated one of my projects from .net 4.0 to 4.5, the reason probably was because there was another .edmx file in an other project that was referenced in the target project.
Solution to issue : Updated the other project that was referenced and contained .edmx file to .net 4.5 and then, Right-Clicked on every .edmx files in these 2 projects and then selected 'Run Custom Tool'
It worked for me, hope that it works for everyone reading this article

Related

Why integration bus executes 3 times on CreateObject event and why sitename is null during outgoing synchronisation in Kentico?

I've installed a fresh new version of Kentico v12 and i'm using the basic goat template.
I would like to be able to synchronize the creation of users and updating of personal informations of those users in the frontend application with a SAP webservice.
I've added a new custom field in the user object "SAPID" and created a connector to manage the synchronization with SAP webservices.
Here is my poc code:
public class CMSIntegrationConnector : BaseIntegrationConnector
{
/// <summary>
/// Initializes the connector name.
/// </summary>
public override void Init()
{
// Initializes the connector name (must match the code name of the connector object in the system)
// GetType().Name uses the name of the class as the ConnectorName
ConnectorName = GetType().Name;
SubscribeToObjects(TaskProcessTypeEnum.AsyncSimple, PredefinedObjectType.USER);
}
public override IntegrationProcessResultEnum ProcessInternalTaskAsync(GeneralizedInfo infoObj, TranslationHelper translations, TaskTypeEnum taskType, TaskDataTypeEnum dataType, string siteName, out string errorMessage)
{
try
{
if (siteName == "DancingGoat")
{
if (infoObj.TypeInfo.ObjectType == PredefinedObjectType.USER.ToString())
{
if (taskType == TaskTypeEnum.CreateObject)
{
EventLogProvider.LogInformation("Connector", "CreateUser", "User created on SAP !!!!!");
UserInfo user = infoObj.MainObject as UserInfo;
// Call SAP webservice
user.SetValue("SAPID", Guid.NewGuid());
UserInfoProvider.SetUserInfo(user);
}
else if (taskType == TaskTypeEnum.UpdateObject)
{
EventLogProvider.LogInformation("Connector", "CreateUser", "User updated on SAP !!!!!");
// Call SAP webservice
}
}
}
}
catch (Exception ex)
{
EventLogProvider.LogException("Connector", "CreateUser", ex);
errorMessage = ex.Message;
return IntegrationProcessResultEnum.Error;
}
errorMessage = null;
return IntegrationProcessResultEnum.OK;
}
}
Here is a dump of the values of parameters I get when I debug on a createobject event:
I have 2 issues.
Why the parameter sitename is null ?
Why it's executed 3 times successively on each CreateObject event ?
I've checked this post: Kentico 12 DancingGoat MVC SiteName is empty or null
Adding "localhost" in the domain alias of the site didn't work.
Thank you by advance !
With the comment of Enn I understood that my problem came from this instruction "UserInfoProvider.SetUserInfo(user);"
I subscribed to apply a logic on any new User objects and update it again in the logic, that's why I it was executed more than once.
To solve it, I applied the proposition of Michal
using (CMSActionContext context = new CMSActionContext())
{
context.LogWebFarmTasks = false;
context.LogEvents = false;
context.LogExport = false;
context.LogIntegration = false;
context.LogSynchronization = false;
UserInfo user = infoObj.MainObject as UserInfo;
user.SetValue("SAPID", Guid.NewGuid());
UserInfoProvider.SetUserInfo(user);
}
Thank you !

log4net smtpappender custom email recipients

I am able to use log4net to send logging information to an email address using the smtpappender and a Gmail account in a VB solution (Visual Studio 2010). The recipient is configured in the log4net config file, however I would like to be able to change the recipient email address dynamically.
Is it possible without having to write a custom smtpappender?
Wether the answer is yes or no, please give me an example, preferably in VB.
It's not possible, the current SmtpAppender won't allow it. But you're lucky, the SendBuffer in the SmtpAppender can be overridden, so you can easily add some behavior to it. I think your best bet is to use the LoggingEvent properties to set the recipient:
public class MySmtpAppender : SmtpAppender
{
protected override void SendBuffer(log4net.Core.LoggingEvent[] events)
{
var Recipients = events
.Where(e => e.Properties.Contains("recipient"))
.Select(e => e.Properties["recipient"])
.Distinct();
var RecipientsAsASingleLine = string.Join(";", Recipients.ToArray()); // or whatever the separator is
var PreviousTo = To;
To = RecipientsAsASingleLine;
base.SendBuffer(events);
To = PreviousTo;
}
}
You may want to change the way to select recipients, your call.
edit The tool recommended by stuartd works quite well (well, it is quite a simple class, but still):
Public Class MySmtpAppender
Inherits SmtpAppender
Protected Overrides Sub SendBuffer(events As log4net.Core.LoggingEvent())
Dim Recipients = events.Where(Function(e) e.Properties.Contains("recipient")).[Select](Function(e) e.Properties("recipient")).Distinct()
Dim RecipientsAsASingleLine = String.Join(";", Recipients.ToArray())
' or whatever the separator is
Dim PreviousTo = [To]
[To] = RecipientsAsASingleLine
MyBase.SendBuffer(events)
[To] = PreviousTo
End Sub
End Class
it is possible. see my answer in this question - copied code below
using System;
using System.IO;
using System.Web.Mail;
using log4net.Layout;
using log4net.Core;
using log4net.Appender;
namespace SampleAppendersApp.Appender
{
/// <summary>
/// Simple mail appender that sends individual messages
/// </summary>
/// <remarks>
/// This SimpleSmtpAppender sends each LoggingEvent received as a
/// separate mail message.
/// The mail subject line can be specified using a pattern layout.
/// </remarks>
public class SimpleSmtpAppender : AppenderSkeleton
{
public SimpleSmtpAppender()
{
}
public string To
{
get { return m_to; }
set { m_to = value; }
}
public string From
{
get { return m_from; }
set { m_from = value; }
}
public PatternLayout Subject
{
get { return m_subjectLayout; }
set { m_subjectLayout = value; }
}
public string SmtpHost
{
get { return m_smtpHost; }
set { m_smtpHost = value; }
}
#region Override implementation of AppenderSkeleton
override protected void Append(LoggingEvent loggingEvent)
{
try
{
StringWriter writer = new StringWriter(System.Globalization.CultureInfo.InvariantCulture);
string t = Layout.Header;
if (t != null)
{
writer.Write(t);
}
// Render the event and append the text to the buffer
RenderLoggingEvent(writer, loggingEvent);
t = Layout.Footer;
if (t != null)
{
writer.Write(t);
}
MailMessage mailMessage = new MailMessage();
mailMessage.Body = writer.ToString();
mailMessage.From = m_from;
mailMessage.To = m_to;
if (m_subjectLayout == null)
{
mailMessage.Subject = "Missing Subject Layout";
}
else
{
StringWriter subjectWriter = new StringWriter(System.Globalization.CultureInfo.InvariantCulture);
m_subjectLayout.Format(subjectWriter, loggingEvent);
mailMessage.Subject = subjectWriter.ToString();
}
if (m_smtpHost != null && m_smtpHost.Length > 0)
{
SmtpMail.SmtpServer = m_smtpHost;
}
SmtpMail.Send(mailMessage);
}
catch(Exception e)
{
ErrorHandler.Error("Error occurred while sending e-mail notification.", e);
}
}
override protected bool RequiresLayout
{
get { return true; }
}
#endregion // Override implementation of AppenderSkeleton
private string m_to;
private string m_from;
private PatternLayout m_subjectLayout;
private string m_smtpHost;
}
}
You can use log4Net.GlobalContext class.
code:
App.config
<appender name="SmtpLogAppender" type="log4net.Appender.SmtpAppender">
<to type="log4net.Util.PatternString" value="%property{SenderList}"/>
C# Code
GlobalContext.Properties["SenderList"] = "abc#xyz.com, def#xyz.com";
log4net.Config.XmlConfigurator.Configure();
It is possible, to a certain degree, to get dynamic recipient.
In the SMTP appender the replacements for To, CC, From etc is done during configuration. Not ideal (would be best if it were to calculate the values at every send) but still workable.
Re-configuring the logging is not free but is doable programatically. You can set your To field as such :
<to type="log4net.Util.PatternString" value="SomeAccountThatReceivesAll#yourCorp.com%property{MailRecipient}" />
then in your code you can set a comma separated list of recipient like this :
log4net.GlobalContext.Properties["MailRecipient"] = "SomeOtherAccount#yourCorp.com,YourCorpSupportForThisApp#yourCorp.com";
the important bit is that you force a re-configuration AFTER you set these values. The exact syntax will depend on your config strategy, we use a central config file for all the logging so in C# it would look like this :
log4net.Config.XmlConfigurator.ConfigureAndWatch("PathToYourCentralFile.xml");
and voila ! Dynamic recipient without any custom appenders !
Personally I would prefer the custom appender, less hackish as it does not require constant re-configuring if you need to change them often. But if you only need the 10 minute fix and the config for recipient does not change once started then I found this to be good enough.

How to initialize RavenDb database with bundle programatically?

I have this code it works well EXCEPT I want to ensure that the expiration bundle is in the database and I dont want to create this database manually. What is the correct way to initialize a database with the expiration bundle enabled?
_documentStore = new DocumentStore()
{
Url = SettingsManager.RavenDbUrl,
DefaultDatabase = SettingsManager.RavenDbDatabaseName
};
_documentStore.Initialize();
Well I couldnt find docs and I couldnt find help so I cobbled this together:
static class RavenDbExtensions
{
/// <summary>
/// Ensure a bundle is activated
/// </summary>
/// <param name="documentStore"></param>
/// <param name="bundleName"></param>
/// <param name="databaseName"></param>
public static void ActivateBundle(this IDocumentStore documentStore, string bundleName, string databaseName)
{
using (var session = documentStore.OpenSession())
{
var databaseDocument = session.Load<DatabaseDocument>("Raven/Databases/" + databaseName);
var settings = databaseDocument.Settings;
var activeBundles = settings.ContainsKey(Constants.ActiveBundles) ? settings[Constants.ActiveBundles] : null;
if (string.IsNullOrEmpty(activeBundles))
settings[Constants.ActiveBundles] = bundleName;
else if (!activeBundles.Split(new char[]{';'}).Contains(bundleName, StringComparer.OrdinalIgnoreCase))
settings[Constants.ActiveBundles] = activeBundles + ";" + bundleName;
session.SaveChanges();
}
}
}
Then I do this little dance when initializing the document store. It seems to work well. It isnt clear whether the bundle is named Expiration or DocumentExpiration so I try both it doesnt crash and it seems to fold in the expiration functionality I need.
_documentStore = new DocumentStore()
{
Url = SettingsManager.RavenDbUrl
};
_documentStore.Initialize();
_documentStore.ActivateBundle("Expiration", Assembly.GetExecutingAssembly().GetName().Name);
_documentStore.ActivateBundle("DocumentExpiration", Assembly.GetExecutingAssembly().GetName().Name);
_documentStore.DefaultDatabase = Assembly.GetExecutingAssembly().GetName().Name;

Cannot create list in SharePoint 2010 using Client Object Model

I am trying to utilize SharePoint 2010 Client Object Model to create a List based on a custom template. Here's my code:
public void MakeList(string title, string listTemplateGUID, int localeIdentifier)
{
string message;
string listUrl;
ListTemplate template;
ListCreationInformation listInfo;
ListTemplateCollection templatesCollection;
try
{
listUrl = title.Replace(spaceChar, string.Empty);
templatesCollection = clientContext.Site.GetCustomListTemplates(clientContext.Web);
clientContext.Load(templatesCollection);
clientContext.ExecuteQuery();
foreach (ListTemplate t in templatesCollection)
{
if (t.InternalName == listTemplate)
{
template = t;
break;
}
}
listInfo = new ListCreationInformation();
listInfo.TemplateType = template.ListTemplateTypeKind;
//listInfo.TemplateFeatureId = template.FeatureId;
listInfo.Url = listUrl;
listInfo.Title = title;
listInfo.Description = string.Empty;
listInfo.QuickLaunchOption = QuickLaunchOptions.On;
site.Lists.Add(listInfo);
clientContext.ExecuteQuery();
return RetrieveList(title, listUrl);
}
catch (ServerException ex)
{
//...
}
}
A few unexpected things happen when this code is run:
My template is derived from the default document library template. Now, the code above does not create the document library based on my template - it creates the default document library instead.
If I uncomment the //listInfo.TemplateFeatureId = template.FeatureId; the code throws the ServerException error: "Cannot complete this action. Please try again."
If I place listInfo.TemplateFeatureId = template.FeatureId; before listInfo.TemplateType = template.ListTemplateTypeKind; the end result is the same as under item 1 - the default document library is created.
Could anyone please help me realize what am I doing wrong? Thanks.

Transition workflows of a work item's states

I am developing a windows app that performs some common TFS tasks using the 2010 Beta 2 API (like creating new team projects, new work items, selective build, etc. ).
In the process of editing existing work items, I should be able to automatically set the 'Reason' field's values according to state change of the WI (mimic-ing Visual Studio). (eg)- When I edit a bug, when state changes from Active to Resolved, the default Reason is 'Fixed' and similarly the default Reason='Deferred' when state goes from Active to Closed. (As defined in the work item type definition xml file. ) This transition is easy to capture and implement inside a simple event handler on the form, since the initial state will be Active when the Bug is edited for the first time.
I want to know how to implement the remaining transitions like Resolved to Closed (Reason=Fixed), Resolved to Active (Reason=Test failed/Not fixed) or Closed to Active (Reason=Reactivated/Regression).
I know there is a method called WorkItem.GetNextState(current_state,action), but this doesn't help as it requires a specific action.
What I have done so far is shown below:
void cmbBugState_SelectedIndexChanged(object sender, EventArgs e)
{
//private enum bugWorkFlows{"Fixed","Deferred","Duplicate","As Designed","Cannot Reproduce","Obsolete","Test Failed","Not Fixed","Reactivated","Regression"}
string[] activeToResolvedReasons = { "Fixed", "Deferred", "Duplicate", "As Designed", "Cannot Reproduce", "Obsolete" };
string[] resolvedToActiveReasons = { "Test Failed", "Not fixed" };
string[] resolvedToClosedReasons = activeToResolvedReasons;
string[] closedToActiveReasons = { "Reactivated", "Regression" };
string[] activeToClosedReasons = activeToResolvedReasons;
cmbBugReason.Items.AddRange(activeToResolvedReasons);
// Set the default reason according to change of state of the work item.
if (cmbBugState.SelectedItem.ToString() == "Resolved")
{
cmbBugReason.Enabled = true;
cmbBugReason.SelectedItem = activeToResolvedReasons[0];
}
if (cmbBugState.SelectedItem.ToString() == "Closed")
{
cmbBugReason.Enabled = true;
cmbBugReason.SelectedItem = activeToResolvedReasons[1];
}
}
Can anyone show how to handle these events on the form?
Thanks,
Tara.
I tried GetNextState. It was never reliable enough for what I needed.
So I "rolled my own" state transition code that has worked very well for me when I am moving from State "A" to State "B". It is a bit long, but it should have what you are looking for in it.
As a side note: Because this does not use the GetNextState method it has to get the next state somehow. The way it does this is by downloading the XML of the work item type in question. It parses that out and uses that to make a Transition list (_allTransistions).
The permissions levels in TFS 2010 needed to do this are: Team Foundation Administrators or Project Administrators. (As a side note, in TFS 2008 and 2005 all valid users could do this.)
The full code that uses this can be found in the WorkItemHelpers.cs file in the TFS Aggregator project on codeplex.
public static void TransitionToState(this WorkItem workItem, string state, string commentPrefix)
{
// Set the sourceWorkItem's state so that it is clear that it has been moved.
string originalState = (string)workItem.Fields["State"].Value;
// Try to set the state of the source work item to the "Deleted/Moved" state (whatever is defined in the file).
// We need an open work item to set the state
workItem.TryOpen();
// See if we can go directly to the planned state.
workItem.Fields["State"].Value = state;
if (workItem.Fields["State"].Status != FieldStatus.Valid)
{
// Revert back to the orginal value and start searching for a way to our "MovedState"
workItem.Fields["State"].Value = workItem.Fields["State"].OriginalValue;
// If we can't then try to go from the current state to another state. Saving each time till we get to where we are going.
foreach (string curState in workItem.Type.FindNextState((string)workItem.Fields["State"].Value, state))
{
string comment;
if (curState == state)
comment = commentPrefix + Environment.NewLine + " State changed to " + state;
else
comment = commentPrefix + Environment.NewLine + " State changed to " + curState + " as part of move toward a state of " + state;
bool success = ChangeWorkItemState(workItem, originalState, curState, comment);
// If we could not do the incremental state change then we are done. We will have to go back to the orginal...
if (!success)
break;
}
}
else
{
// Just save it off if we can.
string comment = commentPrefix + "\n State changed to " + state;
ChangeWorkItemState(workItem, originalState, state, comment);
}
}
private static bool ChangeWorkItemState(this WorkItem workItem, string orginalSourceState, string destState, String comment)
{
// Try to save the new state. If that fails then we also go back to the orginal state.
try
{
workItem.TryOpen();
workItem.Fields["State"].Value = destState;
workItem.History = comment;
workItem.Save();
return true;
}
catch (Exception)
{
// Revert back to the original value.
workItem.Fields["State"].Value = orginalSourceState;
return false;
}
}
/// <summary>
/// Used to find the next state on our way to a destination state.
/// (Meaning if we are going from a "Not-Started" to a "Done" state,
/// we usually have to hit a "in progress" state first.
/// </summary>
/// <param name="wiType"></param>
/// <param name="fromState"></param>
/// <param name="toState"></param>
/// <returns></returns>
public static IEnumerable<string> FindNextState(this WorkItemType wiType, string fromState, string toState)
{
var map = new Dictionary<string, string>();
var edges = wiType.GetTransitions().ToDictionary(i => i.From, i => i.To);
var q = new Queue<string>();
map.Add(fromState, null);
q.Enqueue(fromState);
while (q.Count > 0)
{
var current = q.Dequeue();
foreach (var s in edges[current])
{
if (!map.ContainsKey(s))
{
map.Add(s, current);
if (s == toState)
{
var result = new Stack<string>();
var thisNode = s;
do
{
result.Push(thisNode);
thisNode = map[thisNode];
} while (thisNode != fromState);
while (result.Count > 0)
yield return result.Pop();
yield break;
}
q.Enqueue(s);
}
}
}
// no path exists
}
private static readonly Dictionary<WorkItemType, List<Transition>> _allTransistions = new Dictionary<WorkItemType, List<Transition>>();
/// <summary>
/// Deprecated
/// Get the transitions for this <see cref="WorkItemType"/>
/// </summary>
/// <param name="workItemType"></param>
/// <returns></returns>
public static List<Transition> GetTransitions(this WorkItemType workItemType)
{
List<Transition> currentTransistions;
// See if this WorkItemType has already had it's transistions figured out.
_allTransistions.TryGetValue(workItemType, out currentTransistions);
if (currentTransistions != null)
return currentTransistions;
// Get this worktype type as xml
XmlDocument workItemTypeXml = workItemType.Export(false);
// Create a dictionary to allow us to look up the "to" state using a "from" state.
var newTransistions = new List<Transition>();
// get the transistions node.
XmlNodeList transitionsList = workItemTypeXml.GetElementsByTagName("TRANSITIONS");
// As there is only one transistions item we can just get the first
XmlNode transitions = transitionsList[0];
// Iterate all the transitions
foreach (XmlNode transitionXML in transitions)
{
// See if we have this from state already.
string fromState = transitionXML.Attributes["from"].Value;
Transition transition = newTransistions.Find(trans => trans.From == fromState);
if (transition != null)
{
transition.To.Add(transitionXML.Attributes["to"].Value);
}
// If we could not find this state already then add it.
else
{
// save off the transistion (from first so we can look up state progression.
newTransistions.Add(new Transition
{
From = transitionXML.Attributes["from"].Value,
To = new List<string> { transitionXML.Attributes["to"].Value }
});
}
}
// Save off this transition so we don't do it again if it is needed.
_allTransistions.Add(workItemType, newTransistions);
return newTransistions;
}