I have one question about Windows Workflow Foundation 4. I have an activity named PositionArrayActivity. This activity has a Sequence activity inside it. I need that in Execute method (during the workflow execution) oneFund variable mapping his value to PORTFOLIO_NAME that is created in Create method.... What have I to do to mapping oneFund value to PORTFOLIO_NAME at runtime?
Thanks
public sealed class PositionArrayActivity : NativeActivity, IActivityTemplateFactory
{
[Browsable(false)]
public Dictionary<string, List<Entity>> dictionary = new Dictionary<string, List<Entity>>();
public ActivityAction<Entity[]> Body { get; set; }
public Entity[] PositionList { get; set; }
public SqlDataReader rdr;
public SqlDataReader sdr;
public Entity[] positionArray;
public List<String> fundList;
public String oneFund { get; set; }
public String date { get; set; }
public List<Entity> listToArrayPositions;
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
metadata.AddDelegate(Body);
}
protected override void Execute(NativeActivityContext context)
{
// A lot of code....
}
public Activity Create(DependencyObject target)
{
Variable<string> var = new Variable<string>
{
Name = "PORTFOLIO_NAME"
};
var fef = new PositionArrayActivity();
var aa = new ActivityAction<Entity[]>();
var da = new DelegateInArgument<Entity[]>();
da.Name = "positions";
fef.Body = aa;
aa.Argument = da;
aa.Handler = new Sequence
{
Variables = { var }
};
return fef;
}
}
You need to have an ActivityContext to set a variable value so first move the declaration of the var (did that name actually compile?) to a higher scope.
Then in Execute
var.Set(activityContext, oneFund);
One thing though, the oneFund property will only be set once at application startup so you may have some surprising results. If you wanted that to be for each instance, you need an inargument.
Related
When executing the OpenScript method of my release script I want to store the indexfields, batchfields and variables to lists. I created a snippet for this
Dictionary<string, string> indexFields = new Dictionary<string, string>();
Dictionary<string, string> batchFields = new Dictionary<string, string>();
Dictionary<string, string> kofaxValues = new Dictionary<string, string>();
foreach (Value val in documentData.Values)
{
if (val.TableName.IsEmpty())
{
string sourceName = val.SourceName;
string sourceValue = val.Value;
switch (val.SourceType)
{
case KfxLinkSourceType.KFX_REL_INDEXFIELD:
indexFields.Add(sourceName, sourceValue);
break;
case KfxLinkSourceType.KFX_REL_VARIABLE:
kofaxValues.Add(sourceName, sourceValue);
break;
case KfxLinkSourceType.KFX_REL_BATCHFIELD:
batchFields.Add(sourceName, sourceValue);
break;
}
}
}
I want to do this because I need the field value. Each field name is unique so I can use it as a key.
When storing my custom properties to the ReleaseSetupData I can read them from the ReleaseData. Let's say two custom properties would return me the field name and the field type, so I know that the field is an IndexField and it's name is "MyIndexField".
I can use these information to access the Dictionary<string, string> indexFields and get the value from that Indexfield.
Currently I setup my ReleaseSetupData with this code
releaseSetupData.CustomProperties.RemoveAll();
// Save all custom properties here
releaseSetupData.CustomProperties.Add("myCustomProperty", "fooBar");
releaseSetupData.Links.RemoveAll();
foreach (IndexField indexField in releaseSetupData.IndexFields) // Save all IndexFields
{
releaseSetupData.Links.Add(indexField.Name, KfxLinkSourceType.KFX_REL_INDEXFIELD, indexField.Name);
}
foreach (BatchField batchField in releaseSetupData.BatchFields) // Save all BatchFields
{
releaseSetupData.Links.Add(batchField.Name, KfxLinkSourceType.KFX_REL_BATCHFIELD, batchField.Name);
}
foreach (dynamic batchVariable in releaseSetupData.BatchVariableNames) // Save all Variables
{
releaseSetupData.Links.Add(batchVariable, KfxLinkSourceType.KFX_REL_VARIABLE, batchVariable);
}
When the OpenScript method of my release script gets executed, the dictionaries (shown in the first snippet) stay empty. This is because documentData.Values is empty.
How can I fill documentData.Values?
You can't. The order of events is as follows:
OpenScript() is called - once per batch.
ReleaseDoc() is called - once per document
CloseScript() is called - once per batch.
The Values collection holds information specific to an individual document and as such will be empty during OpenScript(). Sometimes this isn't what you want - you may want to access another document's values, or exporting them all at once - e.g. in a single web service call.
Here's what I would recommend:
Create a wrapper class for Kofax' Document object. Here's my approach (only properties are shown). This class has a constructor that accepts a ReleaseData object as the single parameter, and all respective properties are populated in said contructor.
public class Document
{
public Dictionary<string, string> BatchFields { get; private set; }
public Dictionary<string, string> IndexFields { get; private set; }
public Dictionary<string,string> KofaxValues { get; set; }
public Dictionary<string, string> TextConstants { get; set; }
public Dictionary<string, string> CustomProperties { get; private set; }
public Dictionary<string,string> ConfigurationSettings { get; set; }
public List<Table> Tables { get; private set; }
private List<Column> Columns;
public List<string> ImageFileNames { get; private set; }
public string KofaxPDFFileName { get; private set; }
public string XdcFilePath { get; private set; }
public XDocument XDocument { get; private set; }
public string ImageFilePath { get; private set; }
public string KofaxPDFPath { get; private set; }
public string TextFilePath { get; private set; }
public byte[] BinaryImage { get; private set; }
public char CellSeparator { get; set; }
}
Then, during ReleaseDoc(), I would just add all of my Documents to a collection. Note that the connection documents is a defined as private in your ReleaseScript:
public KfxReturnValue ReleaseDoc()
{
documents.Add(new Document(DocumentData));
}
You can then decide when and where to export your data. It could be during the CloseScript() event as well, but keep in mind that sanity checks and potential exceptions related to document data (invalid index field values, et cetera) must be thrown during ReleaseDoc(). Using a custom wrapper class and a collection adds a lot of flexibility and features native to .NET to your Export Connector, such as LINQ - here's an example (this is impossible with Kofax' COM objects):
var noPdfs = documents.Where(x => x.KofaxPDFPath.Length == 0);
I simply need to map some auto generated classes from database to domain/viewmodels classes. The autogenerated class may have names like customer_id that I want to be mapped with CustomerId. Somehow I want to register my own convention with auto mapper. I have started with following code however the mapped object properties are not populated:
// Generic method that should map source to target
public static TTarget MapWithUnderScoreConvension(TSource source, TTarget target)
{
Mapper.Initialize(cfg=> cfg.AddProfile<AutoMapperUnderScoreProfile>());
Mapper.CreateMap<TSource, TTarget>();
var mapped = Mapper.Map(source, target);
return mapped;
}
// New underscore profile
public class AutoMapperUnderScoreProfile : Profile
{
public AutoMapperUnderScoreProfile()
{
Mapper.Initialize(configuration => configuration.CreateProfile("UnderScoreProfile", UnderScoreProfile));
Mapper.AssertConfigurationIsValid();
}
private void UnderScoreProfile(IProfileExpression profile)
{
profile.SourceMemberNamingConvention = new PascalCaseNamingConvention();
profile.DestinationMemberNamingConvention = new SourceUnderScoreNamingConvension();
}
}
// Convention class
public class SourceUnderScoreNamingConvension : INamingConvention
{
private readonly string _separatorCharacter="_";
private readonly Regex _splittingExpression = new Regex(#"[\p{Lu}0-9]+(?=_?)");
public Regex SplittingExpression { get { return _splittingExpression;} private set{} }
public string SeparatorCharacter { get { return _separatorCharacter; } private set{} }
}
// Test cases
[TestMethod()]
public void Test_Map_Db_Generated_Class_To_Model()
{
var dbGenerated = new QuestionTypeFromDb()
{
QuestionType_Description = "1",
QuestionType_Id = 1,
QuestionType_Is_Default = true,
QuestionType_Is_TimeBased = true,
QuestionType_Sequence = 1,
QuestionType_Time_In_Seconds = 1
};
var mappedObject = AutoMapperHelper<QuestionTypeFromDb, QuestionType>
.MapWithUnderScoreConvension(dbGenerated, new QuestionType());
mappedObject.QuestionTypeId.Should().Be(dbGenerated.QuestionType_Id);
mappedObject.QuestionTypeDescription.Should().Be(dbGenerated.QuestionType_Description);
mappedObject.TimeInSeconds.Should().Be(dbGenerated.QuestionType_Time_In_Seconds);
mappedObject.QuestionTypeSequence.Should().Be(dbGenerated.QuestionType_Sequence);
}
public class TestQuestionWithAnswerType
{
public int QuestionTypeId { get; set; }
public string QuestionTypeDescription { get; set; }
public int QuestionTypeSequence { get; set; }
public bool QuestionTypeIsTimeBased { get; set; }
public int? QuestionTypeTimeInSeconds { get; set; }
public bool QuestionTypeIsDefault { get; set; }
}
any comments will be appreciated.
Update
I have found that the following workaround works:
I simply replaced used this -> to replace 'underscore' with nothing (Mapper.Initialize(c => c.ReplaceMemberName("_", ""));
public static TTarget MapWithUnderScoreConvension(TSource source, TTarget target)
{
Mapper.Initialize(c => c.ReplaceMemberName("_", ""));
//Mapper.Initialize(cfg => cfg.AddProfile<AutoMapperUnderScoreProfile>());
Mapper.CreateMap<TSource, TTarget>();
var mapped = Mapper.Map(source, target);
return mapped;
}
Your regex needs to be changed to : [\p{L}}0-9]+(?=_?)
This will take care of Customer_Id, CUSTOMER_ID, customer_id
The {L} unicode category includes Lu, Lt, Ll, Lm and Lo characters as mentioned here.
Answer is added in the Update section of the question. Basically the solution for me was very simple -> Mapper.Initialize(c => c.ReplaceMemberName("_", ""));
I see numerous examples on foreach collection reference type property update, but not quite what I am struggling with. What if you want to update a property of a property of the reference type item? like so:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public EmployeeType EmpType { get; set; }
}
public class EmployeeType
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Class1
{
private IList<Employee> existingEmp;
public void edit()
{
var dbEmployees = GetExistingEmployees();
IList<Employee> employees = new List<Employee> {
new Employee{ Id = 1, Name="me", EmpType = new EmployeeType { Id = 1}},
new Employee{ Id = 2, Name="me again", EmpType = new EmployeeType { Id = 2}}
};
foreach (var emp in employees)
{
foreach (var oldEmp in dbEmployees)
{
if (emp.Id == oldEmp.Id)
{
UpdateChanges(emp, oldEmp);
existingEmp.Add(oldEmp);
}
}
}
}
private void UpdateChanges(Employee emp, Employee oldEmp){
if (oldEmp.EmpType.Id != emp.EmpType.Id)
{
LogChange();
oldEmp.EmpType.Id = emp.EmpType.Id;
}
}
private void LogChange()
{
throw new NotImplementedException();
}
//data access layer
public IList<Employee> GetExistingEmployees()
{
throw new NotImplementedException();
}
}
The issue here is the last employee in the collection if his/her employee type property Id changed in a ddl, updating it will cascade to all other employees' emp type in the collection. That is nutts. Due to the logging requirement I can not use lambda or other fancy construct. I need hep with fixing this with in foreach or for loops.
EDIT:
As expected the same code structure works somewhere else in my application. I don't get the last item's property updating bleeding to other items' properties.
I solved this using a hacky approach:
private void UpdateChanges(Employee emp, Employee oldEmp){
var oldEmpTemp = GetEmployeeById(oldEmp.Id);
if (oldEmp.EmpType.Id != emp.EmpType.Id)
{
LogChange();
oldEmpTemp.EmpType.Id = emp.EmpType.Id;
}
//instead of updating the collection items
// and bulk updating in the db, update directly in the db
UpdateEmployee(oldEmpTemp);
}
But still can't explain why it's not working for this instance.
I mae a WCF service that contain this method :
public List<LocationDB> GetLocation()
{
List<LocationDB> locations = null;
using (SqlConnection connection = new SqlConnection(conn))
{
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.CommandText = string.Format("Select L_ID ,L_Name from Location");
connection.Open();
//code to fill the locations list..
my problem is when i want to bind the result from this method in my code i do the following.
void MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
client.GetLocationCompleted += new EventHandler<GetLocationCompletedEventArgs>(client_GetLocationCompleted);
client.GetLocationAsync();
}
}
and :
void client_GetLocationCompleted(object sender, GetLocationCompletedEventArgs e)
{
LocationCombo.ItemsSource = e.Result;
LocationCombo.SelectedValuePath =
LocationCombo.DisplayMemberPath =
}
and finally my LocationDB Class that is located in the App_code folder in the asp web site:
[DataContract]
public class LocationDB
{
[DataMember]
public int Lid { get; set; }
[DataMember]
public int SmId { get; set; }
[DataMember]
public string Lname { get; set; }
how can i bind the SelectedValePath and the DisplayMemberPath in code behind not in XAML.
Thanks
From what I can tell you already have everything you need although some of it needs to be in a different order.
void client_GetLocationCompleted(object sender, GetLocationCompletedEventArgs e)
{
LocationCombo.SelectedValuePath = "Lid";
LocationCombo.DisplayMemberPath = "Lname";
LocationCombo.ItemsSource = e.Result;
}
You should be able to set each of them to a string which represents the property (on the bject you're binding to) to use as the SelectedValuePath and DisplayMemberPath respectively:
LocationCombo.SelectedValuePath = "Lid";
LocationCombo.DisplayMemberPath ="Lname";
LocationCombo.ItemsSource = e.Result.ToList();
I have this code:
[Serializable]
[XmlRoot("ISO_CCY_CODES")]
public class IsoCurrencyCodes
{
public IsoCurrencyCodes()
{
IsoCodes = new List<IsoCurrencyCode>();
}
public IsoCurrencyCodes(List<IsoCurrencyCode> isoCodes)
{
IsoCodes = isoCodes;
}
[XmlArrayItem("ISO_CURRENCY")]
public List<IsoCurrencyCode> IsoCodes { get; set; }
public static IEnumerable<IsoCurrencyCode> Get()
{
var doc = XDocument.Parse(XmlStringIsoCodes.XmlSource.Replace("\r\n", ""));
var res = doc.Deserialize<IsoCurrencyCodes>();
return res.IsoCodes;
}
}
[Serializable]
[XmlRoot("ISO_CURRENCY")]
public class IsoCurrencyCode
{
public IsoCurrencyCode()
{
}
[XmlElement(ElementName = "ENTITY")]
public string Entity { get; set; }
[XmlElement(ElementName = "CURRENCY")]
public string Currency { get; set; }
[XmlElement(ElementName = "ALPHABETIC_CODE")]
public string Alpha_Code3 { get; set; }
[XmlElement(ElementName = "NUMERIC_CODE")]
public int NumCode { get; set; }
[XmlElement(ElementName = "MINOR_UNIT")]
public string MinorUnit { get; set; }
}
And this code, for deserialization:
public static XDocument Serialize<T>(this T source)
{
var ser = new XmlSerializer(source.GetType());
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
ser.Serialize(writer, source);
}
return XDocument.Parse(sb.ToString());
}
public static T Deserialize<T>(this XDocument xmlDocument)
{
var xmlSerializer = new XmlSerializer(typeof (T));
using (var reader = xmlDocument.CreateReader())
return (T) xmlSerializer.Deserialize(reader);
}
This is the XML source
But deserialization doesn't work. Please help.
Thanks!
I believe you only want to use XMLArray if you have a collection element for all of the items to sit underneath. For example here it could be ISO_CURRENCIES. I'm assuming you can't change the source in this case, so just use this instead:
[XmlElement("ISO_CURRENCY")]
public List<IsoCurrencyCode> IsoCodes { get; set; }
You should find that works.
Additionally, if you find you have further problems in getting the deserialization classes right, you can have them autogenerated for you from the XML and then you can take a look at the code that is created:
xsd source.xml
xsd source.xsd /c
This will create source.cs which you can then use in your project or adapt for your own uses.
As a further note, you'll find you can't use int for Minor_Unit as it's nullable (look at ANTARCTICA). You can't deserialize straight to an int?, so you'll either have to make it a string or go via another property, look at this question for more information.