Passing collection data to K2 custom service broker method - c#

I have two K2 SmartObjects: SmartObjectA gets a list of objects. SmartObjectB is a custom SmartObject that executes a custom create method with the list returned from SmartObjectA (basic smart object) as input parameter.
In the custom service broker's code behind, I need to deserialize the list value.
How can I pass the list received in K2 as an input parameter for the create method? I am using a multivalue property and assigning SmartObjectA properties to it.
What format does K2 use to serialize multivalues and how can I check what the input value format is so that I can map the list correctly?
SmartObject A Properties:
Name - SOType.Text,
ID - SOType.Number,
Date - SOType.Date,
Description - SOType.Text
SmartObject B - Property to be populated with SmartObjectA's list:
[Property("LineItems", SoType.MultiValue, "LineItems", "The line items.")]
public string LineItems
{
get
{
return _lineItems;
}
set { _lineItems = value; }
}
Input properties and Create method for SmartObjectB:
[SourceCode.SmartObjects.Services.ServiceSDK.Attributes.Method("Create",
MethodType.Create,
"Create",
"Description",
new string[] { "CustomerId", "Date", "DueDate" },
new string[] { "CustomerId", "Date", "DueDate", "LineItems" },
new string[] { "TaxInvoiceId" })]
public TaxInvoice Create()
{
try
{
..deserialize here
}
}

Since you already have 2 different smartobjects, why not consider building a composite smartobject.
Using a composite smartobject, effectively doesnt require you to build a custom service broker.
Composite Smartobject Creation

Related

Is it possible to bind list of strings to Action Result Include property

In in the snippet below
public async Task<ActionResult> CreateAsync([Bind(Include = DataRequestEditProperties)] ComplexModel complexModel)
{
if (ModelState.IsValid)
{
await DocumentDbRepository<ComplexModel>.CreateItemAsync(complexModel);
return RedirectToAction("Index");
}
return View(complexModel);
}
I am currently requesting specific JSON properties to be returned for creating a C# razor view the following way :
CreateAsync([Bind(Include = "list", "of", "about", "50", "strings")]
I'm wondering if it is possible to declare a list of strings somewhere else and referenced variable set somewhere else? Looking for a temporary solution as I am building a prototype and still defining the models of my MVC project. I would like to define what fields I am requesting in a separate file mapped to a variable that describes the query name and holds the list of strings i need to include
Example of declared variables
List<string> DataRequestEditProperties = new List<string> {"bunch", "o", "strings"};
List<string> DataRequestInformativeView = new List<string> {"infoFieldA", "infoFieldB","infoFieldC"};`

Proper way of passing additional view data to EditorFor

If I pass view data like this
#(Html.EditorFor(x => x.User2, "GenericList",
new ViewDataDictionary {
{ "ListType", ListType.CustomValidation },
{ "Param1", ObjectType.Asset },
{ "Param2", "User2" },
{ "DefaultValue", Model.User2 }
}
))
I am unable to access the Values via ViewData["ListType"]. The keys are stored in a property called Keys, and the values are stored in a ICollection property called Values
Passing the ViewData this way
#Html.EditorFor(x => x.User2, "GenericList",
new { ListType = ListType.CustomValidation,
Param1 = ObjectType.Asset,
Param2 = "User2",
DefaultValue = Model.User2
}
)
means I can get the values easily like ViewData["ListType"].
I don't liek the 2nd method of doing things because it's using anonymous types instead of a ViewDataDictionary. How can I use the first method but still call the ViewData as I expect to be,

How do you initialize a FormCollection with properties in .NET?

I've tried the usual way of:
var form = new FormCollection { "WeekList" = weekfilter, "PracticeList" = practicefilter}
and all possible deviations I could think of, but ultimately had to seperate it apart as:
var form = new FormCollection();
form["WeekList"] = weekfilter;
form["PracticeList"] = practicefilter;
How can I initialize this inline? Is it possible? (I'm basically trying to mimic a form being submitted)
If you're using ASP.NET MVC (not core), you can initialize System.Web.Mvc.FormCollection like this:
var form = new FormCollection {
{"WeekList", weekfilter},
{"PracticeList", practicefitler}
}
Demo in .NET Fiddle
But I'm not the right computer to test this. I'm basing this on the .Add method of FormCollection begin declared as:
public virtual void Add(
string name,
string value
)
What types are the filter variables declared as?
If you're using Microsoft.AspNetCore.Http.FormCollection in aspnet core, you can initialize like this:
var formCol = new FormCollection(new Dictionary<string, Microsoft.Extensions.Primitives.StringValues>
{
{ "Field1", "String Value 1" },
{ "Field2", "String Value 2" },
{ "Field3", "String Value 3" }
});
Demo in .NET Fiddle
Then, if you need to create a controller with test data, you can pass to the controller create method like this:
// Call create controller with test data
_controller.Create(formCol);

getting data from list to use in code?

Unfortunately I m new to Lambda/ Linq and I need to get data from a list. Below is my existing code:
Highcharts chart = new Highcharts("chart")
.InitChart(new Chart { DefaultSeriesType = ChartTypes.Bubble, ZoomType = ZoomTypes.Xy, Width = 600, Height = 400 })
.SetTitle(new Title { Text = "Highcharts Bubbles" })
.SetSeries(new[]
{
new Series
{
Name="Buy",
Data = new Data(new object[]
{
new object[] {97,36,79 },
new object[] { 94,74,60 },
new object[] { 68,76,58 }
})
}
});
Lines of code which need to be replaced are:
new object[] {97,36,79 },
new object[] { 94,74,60 },
new object[] { 68,76,58 }
In above code inside {} instead of hardcoded values for example 97, 36, 79 in first line I need to pass values from transactions (transaction volume, price and termdate).
(it is just like using foreach loop but I have to do it using Lambda/ Linq.) I can query all transactions in list transaction.
My poco class is:
public class Transaction : SearchCondition, Automappable
{
[ScriptIgnore]
public virtual int Id { get; set; }
public virtual decimal Volume { get; set; }
public virtual decimal Price { get; set; }
public virtual DateTime TermDate { get; set; }
}
Can you please help me modifying code.
I highly appreciate your time, guidance and help.
EDIT
I have tried the ways mentioned in below solutions, it is almost what is required but still a small issue.
Below codes are able to supply data but they cover data with an additional array. To clear it more please see below image of incorrect structure:
It do not show an error but because of that I am not able to use data.
Below is a snap short of correct data structure.
Can you please help a little more.
How about generating the array like this, where transactionList is your list of transactions:
Data = new Data(transactionList
.Select(i => new object[]
{i.Volume, i.Price, i.TermDate} as object)
.ToArray();
Here you create multiple arrays of objects, one for each of your transaction records. Each of these arrays is treated as a single object in the final array.
Select works by mapping each element of an input IEnumerable (in your case, transactionList), to a function of the element. In your case, your function (the lambda expression inside the Select statement) takes each element, and extract fields into an object array.
The whole operation returns an IEnumerable of object - but your Data constructor takes an object array. So we have to call ToArray() to convert to an object[].
Have you tried using one of the above solutions but not selecting an Array of Arrays?
Using a List<Transaction> called transactions:
Data = new Data(transactions.Select(t => t).ToArray());
This is assuming that the transactions IEnumerable is a collection of Transaction objects, in which case you just want to select every object in the array and pass to the Data classes constructor.
Alternatively, you could also do:
Data = new Data(transactions);
I you have a List<Transaction> object named tList, then your data line would look like this:
Data = new Data(tList
// for each item in the list
.Select(
// create an array of the values we care about
item => new object[] { item.Volume, item.Price, item.TermDate })
// put each of those results into an array
.ToArray());
If you have an IEnumerable of objects you can use the Linq Select method to transform it into an IEnumerable of a different type.
The Select statement takes as a parameter a lambda expression which takes one item from the source IEnumerable and returns a (usually) different type. The results of the lambda expression become the items in a new IEnumerable.
In your case, let's assume that you have a List<Transaction> called transactions that contains all of the Transaction objects you want to display in the graph. Assuming that the items in the list are already sorted into the correct order, you can use the following code to create your Data instance:
Data = new Data(
transactions.Select(t =>
(object)new object[] { t.Volume, t.Price, t.TermDate}
)
.ToArray()
)
In this code the Select method is used to convert your List<Transaction> to IEnumerable<object>, which the ToArray method then converts to object[].
If you need to you can do conversions and calculations on the data inside the lambda expression:
Data = new Data(
transactions.Select(t =>
(object)new object[]
{
(int)t.Volume,
(int)t.Price,
t.TermDate.DayOfYear
}
)
.ToArray()
)
(Edited to return object[] instead of object[][])

Map enum value robustly

I have a form where I collect data from users. When this data is collected, I pass it to various partners, however each partner has their own rules for each piece of data, so this has to be converted. I can make this happen, but my worries are about the robustness. Here's some code:
First, I have an enum. This is mapped to dropdown a dropdown list - the description is the text value, and the int mapped to the value.
public enum EmploymentStatusType
{
[Description("INVALID!")]
None = 0,
[Description("Permanent full-time")]
FullTime = 1,
[Description("Permanent part-time")]
PartTime = 2,
[Description("Self employed")]
SelfEmployed = 3
}
When the form is submitted, the selected value is converted to its proper type and stored in another class - the property looks like this:
protected virtual EmploymentStatusType EmploymentStatus
{
get { return _application.EmploymentStatus; }
}
For the final bit of the jigsaw, I convert the value to the partners required string value:
Dictionary<EmploymentStatusType, string> _employmentStatusTypes;
Dictionary<EmploymentStatusType, string> EmploymentStatusTypes
{
get
{
if (_employmentStatusTypes.IsNull())
{
_employmentStatusTypes = new Dictionary<EmploymentStatusType, string>()
{
{ EmploymentStatusType.FullTime, "Full Time" },
{ EmploymentStatusType.PartTime, "Part Time" },
{ EmploymentStatusType.SelfEmployed, "Self Employed" }
};
}
return _employmentStatusTypes;
}
}
string PartnerEmploymentStatus
{
get { return _employmentStatusTypes.GetValue(EmploymentStatus); }
}
I call PartnerEmploymentStatus, which then returns the final output string.
Any ideas how this can be made more robust?
Then you need to refactor it into one translation area. Could be something like a visitor pattern implementation. Your choices are distribute the code (as you are doing now) or visitor which would centralize it. You need to build in a degree of fragility so your covering tests will show problems when you extend in order to force you to maintain the code properly. You are in a fairly common quandry which is really a code organisational one
I did encounter such a problem in one of my projects and I solved it by using a helper function and conventions for resource names.
The function is this one:
public static Dictionary<T, string> GetEnumNamesFromResources<T>(ResourceManager resourceManager, params T[] excludedItems)
{
Contract.Requires(resourceManager != null, "resourceManager is null.");
var dictionary =
resourceManager.GetResourceSet(culture: CultureInfo.CurrentUICulture, createIfNotExists: true, tryParents: true)
.Cast<DictionaryEntry>()
.Join(Enum.GetValues(typeof(T)).Cast<T>().Except(excludedItems),
de => de.Key.ToString(),
v => v.ToString(),
(de, v) => new
{
DictionaryEntry = de,
EnumValue = v
})
.OrderBy(x => x.EnumValue)
.ToDictionary(x => x.EnumValue, x => x.DictionaryEntry.Value.ToString());
return dictionary;
}
The convention is that in my resource file I will have properties that are the same as enum values (in your case None, PartTime etc). This is needed to perform the Join in the helper function which, you can adjust to match your needs.
So, whenever I want a (localized) string description of an enum value I just call:
var dictionary = EnumUtils.GetEnumNamesFromResources<EmploymentStatusType>(ResourceFile.ResourceManager);
var value = dictionary[EmploymentStatusType.Full];

Categories