I have a net core app using core1.1 When migrating a cript/decript module from an old .NET4.6 to net core it just wont work
First TripleDES no longer (it used to) supports 128bit keys and is fixed with 192bit keys, trying to change it causes error.
Second, while trying to decript this string:
/Tk0ydguv3HauCVUWDK3Tr6U8c9BBaaRwtSt5q4/uHg=
TripleDES launches error with PKCS7 Padding saing "Specified padding mode is not valid for this algorithm." Which is strange since ti is the padding it defaults.
My project.json:
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.0.1",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.AspNetCore.Routing": "1.0.1",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.1",
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
"Microsoft.EntityFrameworkCore.Design": "1.0.0-preview2-final",
"Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.1",
"Microsoft.AspNetCore.Mvc.WebApiCompatShim": "1.0.1",
"Microsoft.AspNetCore.Session": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
},
"tools": {
"BundlerMinifier.Core": "2.0.238",
"Microsoft.EntityFrameworkCore.Tools.DotNet": "1.0.0-preview3-final",
"Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
},
"frameworks": {
"netcoreapp1.1": {
"imports": [
"portable-net461+win8"
]
}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"runtimeOptions": {
"configProperties": {
"System.GC.Server": true
}
},
"publishOptions": {
"include": [
"wwwroot",
"**/*.cshtml",
"appsettings.json",
"web.config"
]
},
"scripts": {
"prepublish": [ "bower install", "dotnet bundle" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
}
My code:
using System;
using System.Security.Cryptography;
using System.Text;
namespace WebApp.Class
{
public class Md5
{
private static readonly byte[] IV = { 240, 3, 45, 29, 0, 76, 173, 59 };
const int NumCryptokey = 6;
const int NumExtraClave = 8;
const int NumsKey = 7;
public static string Generate(int KeyChars)
{
int i_key = 0;
float Random1 = 0;
Int16 arrIndex = default(Int16);
StringBuilder sb = new StringBuilder();
char RandomLetter;
string KeyLetters = "abcdefghijklmnopqrstuvwxyz";
string KeyNumbers = "0123456789";
char[] LettersArray = null;
char[] NumbersArray = null;
LettersArray = KeyLetters.ToCharArray();
NumbersArray = KeyNumbers.ToCharArray();
for (i_key = 1; i_key <= KeyChars; i_key++)
{
Random random = new Random();
Random1 = random.Next();
arrIndex = -1;
if ((Convert.ToInt32(Random1 * 111)) % 2 == 0)
{
while (arrIndex < 0)
{
arrIndex = Convert.ToInt16(LettersArray.GetUpperBound(0) * Random1);
}
RandomLetter = LettersArray[arrIndex];
if ((Convert.ToInt32(arrIndex * Random1 * 99)) % 2 != 0)
{
RandomLetter = LettersArray[arrIndex];
RandomLetter = char.ToUpper(RandomLetter);
}
sb.Append(RandomLetter);
}
else
{
while (arrIndex < 0)
{
arrIndex = Convert.ToInt16(NumbersArray.GetUpperBound(0) * Random1);
}
sb.Append(NumbersArray[arrIndex]);
}
}
return sb.ToString();
}
public static string Encriptar(string serializedQueryString)
{
string functionReturnValue = null;
string sRetorno = null;
try
{
string cryptokey = "";
string ExtraClave = "";
string sKey = "";
cryptokey = Generate(NumCryptokey);
ExtraClave = Generate(NumExtraClave);
sKey = Generate(NumsKey);
byte[] buffer = Encoding.ASCII.GetBytes(serializedQueryString + ExtraClave);
var des = TripleDES.Create();
var MD5 = System.Security.Cryptography.MD5.Create();
des.Key = MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(sKey + cryptokey));
des.IV = IV;
sRetorno = cryptokey + ExtraClave + sKey + Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length));
functionReturnValue = sRetorno;
}
catch (Exception ex)
{
functionReturnValue = "";
}
return functionReturnValue;
}
public static string Desencriptar(string encryptedQueryString)
{
string functionReturnValue = null;
byte[] buffer = null;
var DES = System.Security.Cryptography.TripleDES.Create();
var Md5 = MD5.Create();
string sRetorno = null;
string cryptokey = "";
string ExtraClave = "";
string sKey = "";
cryptokey = encryptedQueryString.Substring(0,NumCryptokey);
ExtraClave = encryptedQueryString.Substring(NumCryptokey, NumExtraClave);
sKey = encryptedQueryString.Substring(NumCryptokey + NumExtraClave, NumsKey);
encryptedQueryString = encryptedQueryString.Substring(NumCryptokey + NumExtraClave + NumsKey, encryptedQueryString.Length-(NumCryptokey + NumExtraClave + NumsKey));
try
{
buffer = Convert.FromBase64String(encryptedQueryString);
byte[] by = new byte[24];
by = Md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(sKey + cryptokey));
Array.Resize(ref by, 24);
DES.Key = by;
DES.IV = IV;
sRetorno = Encoding.ASCII.GetString(DES.CreateDecryptor().TransformFinalBlock(buffer, 0, buffer.Length)).Replace(ExtraClave, "");
functionReturnValue = sRetorno;
}
catch (Exception ex)
{
functionReturnValue = "";
}
return functionReturnValue;
}
}
}
Found it!
public static string Encriptar(string serializedQueryString)
{
string functionReturnValue = null;
string sRetorno = null;
try
{
string cryptokey = "";
string ExtraClave = "";
string sKey = "";
cryptokey = Generate(NumCryptokey);
ExtraClave = Generate(NumExtraClave);
sKey = Generate(NumsKey);
byte[] buffer = Encoding.ASCII.GetBytes(serializedQueryString + ExtraClave);
var des = TripleDES.Create();
var Md5 = MD5.Create();
byte[] by = new byte[24];
by = Md5.ComputeHash(Encoding.ASCII.GetBytes(sKey + cryptokey));
Array.Resize(ref by, 24);
Array.Copy(by, 0, by, 16, 8);
des.Key = by;
des.IV = IV;
//es.Padding = PaddingMode.None;
sRetorno = cryptokey + ExtraClave + sKey + Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buffer, 0, buffer.Length));
functionReturnValue = sRetorno;
}
catch (Exception ex)
{
functionReturnValue = "";
}
return functionReturnValue;
}
I faced the same issue in ASP.NET Core. However, I was not specifying any IV.
I just added this line while encrypting as well as decrypting after specifying the key.
DES3.IV = new byte[DES3.BlockSize / 8];
Without this line, i was getting the error as described above.
As per the docs at https://msdn.microsoft.com/en-us/library/system.security.cryptography.symmetricalgorithm.iv(v=vs.110).aspx
The IV property is automatically set to a new random value whenever
you create a new instance of one of the SymmetricAlgorithm classes or
when you manually call the GenerateIV method.
However, I still do not understand why this worked because even i tried giving static values to the IV(like yours in question) & it failed even then.
Related
Is there a good way to handle the ProvisionedThroughputExceededException without increasing the Read/Write capacity of the table? Ideally, I would like to decrease the throughput on the scripting side such that the exception won't be triggered.
function saveDataToDynamodb(data, scriptName){
let items = [];
var processItemsCallback = function (err, data) {
if (err) {
console.log(err);
setTimeout(() => {console.log('sleep for error')}, Math.floor(0.5 * 1000 + 1000));
}else {
if (Object.keys(data.UnprocessedItems).length > 0) {
//setTimeout(() => {console.log('sleep to wait')}, Math.floor(Math.random() * 1000 + 1000));
var params = {};
params.RequestItems = data.UnprocessedItems;
docClient.batchWrite(params, processItemsCallback);
}
}
};
data.forEach(station => {
let stationName = station.stationName
if (stationName == null) {
stationName = "null"
}
//console.log(station.stationId + "_" + stationName)
let pollutants = station.pollutants
let unique_set = new Set()
let aqiArr = [];
let sortedKey;
let timestamp;
pollutants.forEach(pollutant => {
timestamp = pollutant.utcMoment
sortedKey = station.stationId + "_" + timestamp + "_" + station.latitude + "_" + station.longitude + "_" + pollutant.pollutant;
if (!unique_set.has(sortedKey)) {
unique_set.add(sortedKey)
if (!scriptName.includes("Pollen")) { // calculate AQI if it's not pollen data
let polValue = processPollutant(pollutant.value, pollutant.pollutant);
let pollutantAQI;
if (pollutant.pollutant == "o3" && pollutant.avgInterval == "1h") {
pollutantAQI = aqiCalc.calcEpaAqi(polValue, pollutant.pollutant, true);
} else {
pollutantAQI = aqiCalc.calcEpaAqi(polValue, pollutant.pollutant, false);
}
//console.log("polValue: " + polValue + ", Pollutant value: " + pollutant.value + ", pollutant: " + pollutant.pollutant + ", AQI: " + pollutantAQI)
aqiArr.push(pollutantAQI);
}
items.push({
PutRequest: {
Item: {
"stationId": station.stationId,
"stationName": String(station.stationName),
"latitude": station.latitude,
"longitude": station.longitude,
"pollutant": pollutant.pollutant,
"avgInterval": pollutant.avgInterval,
"units": pollutant.units,
"initialUnits": pollutant.initialUnits,
"value": pollutant.value,
"sortedKey": sortedKey,
"timestamp": timestamp
}
}
});
if (items.length >= 24) {
let params = {
RequestItems: {
pollutantFullData: items
}
};
docClient.batchWrite(params, processItemsCallback);
items = []
}
}
});
if (aqiArr.length > 0) {
var finalAqi = getMaxAsInteger(aqiArr);
if (finalAqi > 500) {
finalAqi = 500;
}
items.push({
PutRequest: {
Item: {
"stationId": station.stationId,
"stationName": String(station.stationName),
"latitude": station.latitude,
"longitude": station.longitude,
"pollutant": "aqi",
"avgInterval": "1h",
"units": "ppb",
"initialUnits": "ppm",
"value": finalAqi,
"sortedKey": station.stationId + "_" + timestamp + "_" + station.latitude + "_" + station.longitude + "_aqi",
"timestamp": timestamp
}
}
});
}
if (items.length > 0) {
let params = {
RequestItems: {
pollutantFullData: items
}
};
docClient.batchWrite(params, processItemsCallback);
}
});
}
It seems as though the batchWrite operation is running asynchronously, such that the various threads are hitting the API endpoint at the same time, thus causing the error. How can the previous code be changed to resolve the error?
I have the following data structure that I'm looking to transform. The structure exist as follows:
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"providers": [
{
"providerNumber": "157833AC",
"providerName": "DR TEST"
}
],
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "First Assessment",
"fee": 50,
"isPracticeReferenceItem": "true"
}
]
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "Consult One",
"fee": 23.35,
"isPracticeReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
}
]
}
]
}
I'm wanting a query that returns the id, practiceId and extrasCoverservices (serviceTypeName, serviceTypeCode and the serviceItems). I don't want to include the provider information.
I've tried this, but I need to specify the position of the element in the array which I don't want to do. Any help would be much appreciated.
SELECT a.id
, a.practiceId
, [{"serviceTypeName": a.extrasCoverServices[0].serviceTypeName, "serviceTypeCode": a.extrasCoverServices[0].serviceTypeCode, "serviceItems": a.extrasCoverServices[0].serviceItems}]
Update
function sample(documentId) {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT ARRAY_CONCAT([{"itemId": s.itemId, "itemName": s.itemName,"itemNumber":s.itemNumber,"fee":s.fee,"isReferenceItem":s.isReferenceItem}], IS_DEFINED(s.customisations) ? s.customisations : []) as extrasCoverServices FROM a JOIN e in a.extrasCoverServices JOIN s in e.serviceItems WHERE a.id =' + "'" + documentId + "'",
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
console.log(feed.length);
var result = feed.flatten(function(x) {
return x.extrasCoverServices;
});
getContext().getResponse().setBody(result);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
You almost had it. To achieve this, you can use features:
inner-document joining using join keyword
explicit JSON composition using { and } wrappers
The first gives you access to the subItem you want to cherry-pick and the second enables you to glue them back together they way you like it.
The query you are looking for should be along the lines of this:
SELECT
a.id,
a.practiceId,
[{
"serviceTypeName": e.serviceTypeName,
"serviceTypeCode" : e.serviceTypeCode,
"serviceItems": e.serviceItems
}] as extrasCoverServices
FROM a
join e in a.extrasCoverServices
Note that you can combine Sql-like select with explicit JSON building in the same query to keep the query more compact. Also, I suggest you use CosmosDB SQL query cheat sheet to easily discover, what's in the toolbox.
function sample(documentId, itemId) {
var collection = getContext().getCollection();
var query = 'SELECT e.serviceTypeCode, '+
' e.serviceTypeName, '+
' s.itemNumber, '+
' ARRAY_CONCAT( '+
' [{ '+
' "itemId": s.itemId, '+
' "itemName": s.itemName, '+
' "fee":s.fee, '+
' "isReferenceItem":s.isReferenceItem '+
' }], '+
' IS_DEFINED(s.customisations) ? s.customisations : []) as extrasCoverServices '+
' FROM a '+
' JOIN e in a.extrasCoverServices '+
' JOIN s in e.serviceItems '+
' WHERE a.id = ' + "'" + documentId + "'";
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
query,
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
var returnResult = [];
for(var i = 0; i<feed.length; i++) {
let serviceItem = feed[i];
let serviceItemsArray = feed[i].extrasCoverServices;
for(var j = 0; j < serviceItemsArray.length; j++) {
let item = serviceItemsArray[j];
let mapped = {
serviceTypeCode: serviceItem.serviceTypeCode
, serviceTypeName: serviceItem.serviceTypeName
, itemId: item.itemId
, itemName: (item.itemName ? item.itemName : item.practiceDisplayName)
, itemNumber: serviceItem.itemNumber
, fee: item.fee
, isReferenceItem: ((item.isReferenceItem && item.isReferenceItem == true) ? item.isReferenceItem: false)
, isPracticeReferenceItem: (item.isPracticeReferenceItem && item.isPracticeReferenceItem == true ? item.isPracticeReferenceItem : false)
};
returnResult.push(mapped);
}
}
if(itemId != undefined) {
var filteredReturnResult = returnResult.filter(r => r.itemId == itemId);
getContext().getResponse().setBody(filteredReturnResult);
return
}
getContext().getResponse().setBody(returnResult);
if (!isAccepted) throw new Error('The query was not accepted by the server.');
})
}
Please use sql like:
SELECT a.id,a.practiceId,e.serviceTypeName,e.serviceTypeCode,e.serviceItems
FROM a
join e in a.extrasCoverServices a
Result:
If you want to make the e.serviceTypeName,e.serviceTypeCode,e.serviceItems into an array, not parallel with id and praticeId, I suggest you using stored procedure in cosmos db.
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT c.id,c.practiceId,c.extrasCoverServices FROM root c',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
var returnResult = [];
for(var i = 0;i<feed.length;i++){
var obj1 = {
id:"",
practiceId:"",
serviceArray :[]
};
obj1.id = feed[i].id;
obj1.practiceId = feed[i].practiceId;
var loopArray = feed[i].extrasCoverServices;
var serviceResult = [];
for(var j = 0;j<loopArray.length;j++){
var obj2 = {
serviceTypeName:"",
serviceTypeCode:"",
serviceItems:[] };
obj2.serviceTypeName=loopArray[j].serviceTypeName;
obj2.serviceTypeCode=loopArray[j].serviceTypeCode;
obj2.serviceItems=loopArray[j].serviceItems;
serviceResult.push(obj2);
}
obj1.serviceArray= serviceResult;
returnResult.push(obj1);
}
getContext().getResponse().setBody(returnResult);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Result:
Hope it helps you.
Update Answer 1:
For your further requirement in your comment, I test a sql for you.
SELECT
a.id,
a.practiceId,
[{
"serviceTypeName": e.serviceTypeName,
"serviceTypeCode" : e.serviceTypeCode,
"serviceItems": [
{"itemName": s.itemName,
"itemNumber":s.itemNumber,
"fee":s.fee,
"isReferenceItem":s.isReferenceItem
},
{"practiceDisplayName":c.practiceDisplayName,
"itemNumber":s.itemNumber,
"fee": c.fee,
"isPracticeReferenceItem":c.isPracticeReferenceItem
}
]
}] as extrasCoverServices
FROM a
join e in a.extrasCoverServices
join s in e.serviceItems
join c in s.customisations
However , the results have multiple items because of the join.
[
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "First Assessment",
"itemNumber": "100",
"fee": 50,
"isPracticeReferenceItem": "true"
}
]
}
]
},
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult One",
"itemNumber": "200",
"fee": 23.35,
"isPracticeReferenceItem": "true"
}
]
}
]
},
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"itemNumber": "200",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
}
]
}
]
So, I suggest you processing the results in the stored procedure to match your requirement.
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT a.id, a.practiceId,'+
'[{'+
'"serviceTypeName": e.serviceTypeName, '+
'"serviceTypeCode" : e.serviceTypeCode, '+
'"serviceItems": ['+
'{"itemName": s.itemName,'+
'"itemNumber":s.itemNumber,'+
'"fee":s.fee,'+
'"isReferenceItem":s.isReferenceItem'+
'},'+
'{"practiceDisplayName":c.practiceDisplayName,'+
'"itemNumber":s.itemNumber,'+
'"fee": c.fee,'+
'"isPracticeReferenceItem":c.isPracticeReferenceItem '+
'}'+
']'+
'}] as extrasCoverServices'+
' FROM a '+
' join e in a.extrasCoverServices'+
' join s in e.serviceItems'+
' join c in s.customisations',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
var returnResult = [];
var obj1 = {
id:"",
practiceId:"",
extrasCoverServices :[]
};
var temp = "";
for(var i = 0;i<feed.length;i++){
if(temp==feed[i].id){
var extrasArray = obj1.extrasCoverServices[0].serviceItems;
var serviceArray = feed[i].extrasCoverServices[0].serviceItems;
for(var j = 0;j<serviceArray.length;j++){
extrasArray.push(serviceArray[j]);
}
obj1.extrasCoverServices[0].serviceItems = extrasArray;
} else{
obj1.id = feed[i].id;
obj1.practiceId = feed[i].practiceId;
obj1.extrasCoverServices = feed[i].extrasCoverServices;
temp = feed[i].id;
}
}
returnResult.push(obj1);
getContext().getResponse().setBody(returnResult);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Process Result:
[
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "First Assessment",
"itemNumber": "100",
"fee": 50,
"isPracticeReferenceItem": "true"
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult One",
"itemNumber": "200",
"fee": 23.35,
"isPracticeReferenceItem": "true"
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"itemNumber": "200",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
}
]
}
]
Update Answer 2:
Well,I still focus on implementing your needs through the Stored Procedure.
I add one item without customisations array into serviceItems as below:
[
{
"id": "13fd6574-dc33-4b8c-a09b-a937869d184f",
"practiceId": 2,
"extrasCoverServices": [
{
"serviceTypeName": "OCCUPATIONAL THERAPY",
"serviceTypeCode": "H",
"serviceItems": [
{
"itemName": "INITIAL CONS",
"itemNumber": "100",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "First Assessment",
"fee": 50,
"isPracticeReferenceItem": "true"
}
]
},
{
"itemName": "CONS TREAT",
"itemNumber": "200",
"fee": 0,
"isReferenceItem": "true",
"customisations": [
{
"practiceDisplayName": "Consult One",
"fee": 23.35,
"isPracticeReferenceItem": "true"
},
{
"practiceDisplayName": "Consult Two",
"fee": 15,
"isPracticeReferenceItem": "false"
}
]
},
{
"itemName": "FOR TEST",
"itemNumber": "333",
"fee": 20,
"isReferenceItem": "true"
}
]
}
]
}
]
SP CODE:
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT a.id, a.practiceId,'+
'[{'+
'"serviceTypeName": e.serviceTypeName, '+
'"serviceTypeCode" : e.serviceTypeCode, '+
'"serviceItems": e.serviceItems'+
'}] as extrasCoverServices'+
' FROM a '+
' join e in a.extrasCoverServices',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
for(var i = 0;i<feed.length;i++){
var extraArray = feed[i].extrasCoverServices;
for(var j = 0;j<extraArray.length;j++){
var serviceArray = extraArray[j].serviceItems;
var array = [];
for(var k = 0;k<serviceArray.length;k++){
var o1 = {
"itemName": "",
"itemNumber":"",
"fee" : "",
"isReferenceItem":""
};
console.log(k+"----");
o1.itemName = serviceArray[k].itemName;
o1.itemNumber = serviceArray[k].itemNumber;
o1.fee = serviceArray[k].fee;
o1.isReferenceItem = serviceArray[k].isReferenceItem;
console.log(o1.itemName);
array.push(o1);
if(null != serviceArray[k].customisations){
var customisationsArray = serviceArray[k].customisations;
for(var p = 0;p<customisationsArray.length;p++){
var o2 = {
"practiceDisplayName": "",
"itemNumber":"",
"fee" : "",
"isPracticeReferenceItem":""
};
o2.practiceDisplayName = customisationsArray[p].practiceDisplayName;
o2.itemNumber = o1.itemNumber;
o2.fee = customisationsArray[p].fee;
o2.isPracticeReferenceItem = customisationsArray[p].isPracticeReferenceItem;
array.push(o2);
}
}
}
feed[i].extrasCoverServices[j].serviceItems = array;
}
}
getContext().getResponse().setBody(feed);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Just for summary, I tidied up your last SP code. This is a good thread.
function sample(documentId, itemId) {
var collection = getContext().getCollection();
var query = 'SELECT e.serviceTypeCode, '+
' e.serviceTypeName, '+
' s.itemNumber, '+
' ARRAY_CONCAT( '+
' [{ '+
' "itemId": s.itemId, '+
' "itemName": s.itemName, '+
' "fee":s.fee, '+
' "isReferenceItem":s.isReferenceItem '+
' }], '+
' IS_DEFINED(s.customisations) ? s.customisations : []) as extrasCoverServices '+
' FROM a '+
' JOIN e in a.extrasCoverServices '+
' JOIN s in e.serviceItems '+
' WHERE a.id = ' + "'" + documentId + "'";
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
query,
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
var returnResult = [];
for(var i = 0; i<feed.length; i++) {
let serviceItem = feed[i];
let serviceItemsArray = feed[i].extrasCoverServices;
for(var j = 0; j < serviceItemsArray.length; j++) {
let item = serviceItemsArray[j];
let mapped = {
serviceTypeCode: serviceItem.serviceTypeCode
, serviceTypeName: serviceItem.serviceTypeName
, itemId: item.itemId
, itemName: (item.itemName ? item.itemName : item.practiceDisplayName)
, itemNumber: serviceItem.itemNumber
, fee: item.fee
, isReferenceItem: ((item.isReferenceItem && item.isReferenceItem == true) ? item.isReferenceItem: false)
, isPracticeReferenceItem: (item.isPracticeReferenceItem && item.isPracticeReferenceItem == true ? item.isPracticeReferenceItem : false)
};
returnResult.push(mapped);
}
}
if(itemId != undefined) {
var filteredReturnResult = returnResult.filter(r => r.itemId == itemId);
getContext().getResponse().setBody(filteredReturnResult);
return
}
getContext().getResponse().setBody(returnResult);
if (!isAccepted) throw new Error('The query was not accepted by the server.');
})
}
I fill grid by ashx file and its work fine.
When i add action in grid ,data of cell shift to right and last column show Null.
Before add Action
After add Action
grid in firebug:
ashx:
public void ProcessRequest(HttpContext context) {
HttpRequest request = context.Request;
HttpResponse response = context.Response;
string _search = request["_search"];
string numberOfRows = request["rows"];
string pageIndex = request["page"];
string sortColumnName = request["sidx"];
string sortOrderBy = request["sord"];
int totalRecords;
Collection<User> users = GetDummyUsers(numberOfRows, pageIndex, sortColumnName, sortOrderBy, out totalRecords);
string output = BuildJQGridResults (users, Convert.ToInt32 (numberOfRows), Convert.ToInt32 (pageIndex), Convert.ToInt32 (totalRecords));
response.Write (output);
}
Create Users:
private Collection<User> GetDummyUsers(string numberOfRows, string pageIndex, string sortColumnName, string sortOrderBy, out int totalRecords) {
var data = new Collection<User> {
new User(){ UserID = 1,UserName = "Bill Gates", FirstName = "Bill", LastName = "Gates",EmailID = "test#microsoft.com", },
new User(){ UserID = 1,UserName = "Bill Gates", FirstName = "Bill", LastName = "Gates",EmailID = "test#microsoft.com", },
new User(){ UserID = 1,UserName = "Bill Gates", FirstName = "Bill", LastName = "Gates",EmailID = "test#microsoft.com", },
};
totalRecords = data.Count;
return data;
}
ConvetTo json:
private string BuildJQGridResults(Collection<User> users, int numberOfRows, int pageIndex, int totalRecords) {
JQGridResults result = new JQGridResults ();
List<JQGridRow> rows = new List<JQGridRow> ();
foreach (User user in users) {
JQGridRow row = new JQGridRow ();
row.id = user.UserID;
row.cell = new string[5];
row.cell[0] = user.UserID.ToString ();
row.cell[1] = user.UserName;
row.cell[2] = user.FirstName;
row.cell[3] = user.LastName;
row.cell[4] = user.EmailID;
rows.Add (row);
}
result.rows = rows.ToArray ();
result.page = pageIndex;
result.total = (totalRecords + numberOfRows - 1) / numberOfRows;
result.records = totalRecords;
return new JavaScriptSerializer ().Serialize (result);
}
grid:
url: 'jqGridHandler.ashx',
datatype: 'json',
autowidth: true,
height: 100,
colNames: ['ACTION', 'ID', 'UserName', 'FirstName', 'LastName', 'EmailID'],
colModel: [
{
name: 'act', width: 100, align: 'center', sortable: false, formatter: 'actions',
formatoptions: {
keys: true,
delOptions: true,
delbutton:true,
editbutton:false
}
},
{ name: 'UserID', width: 100, sortable: true, },
{ name: 'UserName', width: 100, sortable: true },
{ name: 'FirstName', width: 100, sortable: true },
{ name: 'LastName', width: 100, sortable: true },
{ name: 'EmailID', width: 100, sortable: true },
],
rowNum: 20,
loadonce: true,
rowList: [5, 10, 20],
recordpos: "left",
ignoreCase: true,
toppager: true,
viewrecords: true,
sortorder: "desc",
scrollOffset: 1,
});
});
jqGrid is treating actions as real column and it expects data for it. The easiest way out of this is to add empty cell to your row on server side:
private string BuildJQGridResults(Collection<User> users, int numberOfRows, int pageIndex, int totalRecords) {
JQGridResults result = new JQGridResults ();
List<JQGridRow> rows = new List<JQGridRow> ();
foreach (User user in users) {
JQGridRow row = new JQGridRow ();
row.id = user.UserID;
row.cell = new string[6];
row.cell[0] = String.Empty;
row.cell[1] = user.UserID.ToString ();
row.cell[2] = user.UserName;
row.cell[3] = user.FirstName;
row.cell[4] = user.LastName;
row.cell[5] = user.EmailID;
rows.Add (row);
}
result.rows = rows.ToArray ();
result.page = pageIndex;
result.total = (totalRecords + numberOfRows - 1) / numberOfRows;
result.records = totalRecords;
return new JavaScriptSerializer ().Serialize (result);
}
As an alternative you can use jqGrid in repeatItems: false mode. First you need to change the jqGrid initialization script:
$("#UsersGrid").jqGrid({
url: 'jqGridHandler.ashx',
datatype: 'json',
autowidth: true,
height: 100,
colNames: ['ACTION', 'ID', 'UserName', 'FirstName', 'LastName', 'EmailID'],
colModel: [
{ name: 'act', width: 100, align: 'center', sortable: false, formatter: 'actions', formatoptions: { keys: true, delOptions: true, delbutton:true, editbutton:false } },
{ name: 'UserID', width: 100, sortable: true, },
{ name: 'UserName', width: 100, sortable: true },
{ name: 'FirstName', width: 100, sortable: true },
{ name: 'LastName', width: 100, sortable: true },
{ name: 'EmailID', width: 100, sortable: true },
],
rowNum: 20,
loadonce: true,
rowList: [5, 10, 20],
recordpos: 'left',
ignoreCase: true,
toppager: true,
viewrecords: true,
sortorder: 'desc',
scrollOffset: 1,
jsonReader : {
repeatitems: false
}
});
Now on server side you can no longer use array, you have to use object or dictionary. I will show the more generic approach which is dictionary. Assuming your solution is based on this sample, you will have to change JQGridResult class like this:
public class JQGridResults
{
public int page;
public int total;
public int records;
public List<Dictionary<string, string>> rows;
}
Now your method can look like this:
private string BuildJQGridResults(Collection<User> users, int numberOfRows, int pageIndex, int totalRecords) {
JQGridResults result = new JQGridResults();
result.rows = new List<Dictionary<string, string>>();
foreach (User user in users) {
Dictionary<string, string> row = new Dictionary<string, string>();
row.Add("id", user.UserID.ToString());
row.Add("UserID", user.UserID.ToString());
row.Add("UserName", user.UserName);
row.Add("FirstName", user.FirstName);
row.Add("LastName", user.LastName);
row.Add("EmailID", user.EmailID);
result.rows.Add(row);
}
result.page = pageIndex;
result.total = (totalRecords + numberOfRows - 1) / numberOfRows;
result.records = totalRecords;
return new JavaScriptSerializer().Serialize(result);
}
This can be further optimized to avoid sending UserId twice, but this is not what is important from your question point of view.
Code works completely fine in my browser. Try with this code. Hopw it works also just check in your webdeveloper tools are you getting any error there.
Also paste your code for myDelOptions.
$("#datagrid").jqGrid({
url: 'jqGridHandler.ashx',
datatype: 'json',
autowidth: true,
height: 100,
colNames: [ 'ACTION', 'EOSysNum', 'PctIndNum', 'PctLettSubject', 'PctAssignSubject', ],
colModel: [
{
name: 'act', width: 100, align: 'center', sortable: false, formatter: 'actions',
formatoptions: {
keys: true,
delOptions: true,
delbutton:true,
editbutton:false
}
},
{ name: 'EOSysNum', index: 'UserID', width: 50, sortable: true, hidden: false },
{ name: 'PctIndNum', width: 140, sortable: true },
{ name: 'PctLettSubject', width: 140, sortable: true },
{ name: 'PctAssignSubject', width: 100, sortable: true },
],
rowNum: 20,
loadonce: true,
rowList: [5, 10, 20],
recordpos: "left",
ignoreCase: true,
toppager: true,
viewrecords: true,
sortorder: "desc",
scrollOffset: 1,
});
remove direction option from jqgrid and let us know it works or not
I am trying to bind generic list to DropDownList an i am not sure how to continue.
here is my code:
protected void Page_Load(object sender, EventArgs e)
{
List<Paths> paths = new List<Paths>();
paths = GetOriginalPaths();
DropDownList1.DataSource = paths;
DropDownList1.DataTextField = "orignalPathName";
DropDownList1.DataValueField = "orignalPathId";
DropDownList1.DataBind();
}
public class Paths
{
public string orignalPathName;
public int orignalPathId;
public string newPathName;
}
public static List<Paths> GetOriginalPaths()
{
return PrepareOriginalPathsData();
}
public static List<Paths> PrepareOriginalPathsData()
{
List<Paths> objPaths = new List<Paths> {
new Paths{orignalPathName = "comp1", orignalPathId= 1} ,
new Paths{orignalPathName = "comp1", orignalPathId= 1} ,
new Paths{orignalPathName = "comp1", orignalPathId= 1} ,
new Paths{orignalPathName = "comp2", orignalPathId= 2} ,
new Paths{orignalPathName = "comp3", orignalPathId= 3} ,
new Paths{orignalPathName = "comp4", orignalPathId= 4}
};
return objPaths;
}
public static List<Paths> GetNewPaths(int orignalPathId)
{
List<Paths> lstNewPaths = new List<Paths>();
Paths objnewPaths = null;
var newPath = (from np in PrepareNewPathsData() where np.orignalPathId == orignalPathId select new { newpathname = np.newPathName, orgId = np.orignalPathId });
foreach (var np in newPath)
{
objnewPaths = new Paths();
objnewPaths.orignalPathId = np.orgId;
objnewPaths.newPathName = np.newpathname;
lstNewPaths.Add(objnewPaths);
}
return lstNewPaths;
}
public static List<Paths> PrepareNewPathsData()
{
List<Paths> objNewPaths = new List<Paths> {
new Paths{newPathName = "part1", orignalPathId= 1} ,
new Paths{newPathName = "part1", orignalPathId= 1} ,
new Paths{newPathName = "part1", orignalPathId= 1} ,
new Paths{newPathName = "part3", orignalPathId= 2} ,
new Paths{newPathName = "part4", orignalPathId= 3} ,
new Paths{newPathName = "part5", orignalPathId= 4} ,
};
return objNewPaths;
}
Fix it!
I had to add this:
public class Paths
{
public string orignalPathName { get; set; }
public int orignalPathId { get; set; }
public string newPathName { get; set; }
}
Your problem might be from the bind prospective you might bind only if not post back!!
If(!Page.IsPostBack)
{
List<Paths> paths = new List<Paths>();
paths = GetOriginalPaths();
DropDownList1.DataSource = paths;
DropDownList1.DataTextField = "orignalPathName";
DropDownList1.DataValueField = "orignalPathId";
DropDownList1.DataBind();
}
What problem are you encountering exactly?
By the way, the DataValueField should be unique. Aas it is it could cause an issue either with the bind, or on post-back.
I've written some custom model binders (implementing IModelBinder) in our ASP.NET MVC application. I'm wondering what is a good approach to unittest them (binders)?
I did it this way:
var formElements = new NameValueCollection() { {"FirstName","Bubba"}, {"MiddleName", ""}, {"LastName", "Gump"} };
var fakeController = GetControllerContext(formElements);
var valueProvider = new Mock<IValueProvider>();
var bindingContext = new ModelBindingContext(fakeController, valueProvider.Object, typeof(Guid), null, null, null, null);
private static ControllerContext GetControllerContext(NameValueCollection form) {
Mock<HttpRequestBase> mockRequest = new Mock<HttpRequestBase>();
mockRequest.Expect(r => r.Form).Returns(form);
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Expect(c => c.Request).Returns(mockRequest.Object);
return new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object);
}
And then I just passed in the bindingContext variable to the BindModel method of the object that implements the IModelBinder interface.
Here's a simple no-mocks way I wrote for you on my blog assuming you use the ValueProvider and not the HttpContext: http://www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx
[TestMethod]
public void DateTime_Can_Be_Pulled_Via_Provided_Month_Day_Year_Hour_Minute_Second_Alternate_Names()
{
var dict = new ValueProviderDictionary(null) {
{ "foo.month1", new ValueProviderResult("2","2",null) },
{ "foo.day1", new ValueProviderResult("12", "12", null) },
{ "foo.year1", new ValueProviderResult("1964", "1964", null) },
{ "foo.hour1", new ValueProviderResult("13","13",null) },
{ "foo.minute1", new ValueProviderResult("44", "44", null) },
{ "foo.second1", new ValueProviderResult("01", "01", null) }
};
var bindingContext = new ModelBindingContext() { ModelName = "foo", ValueProvider = dict };
DateAndTimeModelBinder b = new DateAndTimeModelBinder() { Month = "month1", Day = "day1", Year = "year1", Hour = "hour1", Minute = "minute1", Second = "second1" };
DateTime result = (DateTime)b.BindModel(null, bindingContext);
Assert.AreEqual(DateTime.Parse("1964-02-12 13:44:01"), result);
}
dict could be refactored like this
FormCollection form = new FormCollection
{
{ "month1", "2" },
{ "day1", "12" },
{ "year1", "1964" },
{ "hour1", "13" },
{ "minute1", "44" },
{ "second1", "01" }
};
var bindingContext = new ModelBindingContext() { ModelName = "foo", ValueProvider = form.ToValueProvider() };