AdaptiveCards with PostBack button - bots

I am trying to replace a HeroCard that has multiple CardAction buttons. I would like to use AdaptiveCards, however, I don't see any documentation that states how to enable postBack from an AdaptiveCard button. I see open browser, and what not, but no postBack.
Is this supported yet?
var cardButtons = new List<CardAction>();
var yesAction = new CardAction()
{
Value = "Yes",
Type = "postBack",
Title = "Yes"
};
cardButtons.Add(yesAction);
var noAction = new CardAction()
{
Value = "Nope",
Type = "postBack",
Title = "No, I'll try it"
};
cardButtons.Add(noAction);
var plCard = new HeroCard()
{
Title = $"Are you sure?",
Buttons = cardButtons
};

Have you tried SubmitAction?
var noAction = new CardAction()
{
Value = "Nope",
Type = SubmitAction.TYPE,
Title = "No, I'll try it"
};

This code renders correctly, even seems to send information back to the bot. But still cannot figure out how to read the data back on the resuming function:
var card = new AdaptiveCard();
card.Body.Add(
new ColumnSet() {
Columns = new List<Column>() {
new Column() {
SelectAction = new SubmitAction() { Data = 3, Title = "Good" },
Items = new List<CardElement>() { new Image() { Url = GeneralStrings.Feedback03 } }
},
new Column() {
SelectAction = new SubmitAction() { Data = 2, Title = "Average" },
Items = new List<CardElement>() { new Image() { Url = GeneralStrings.Feedback02 } }
},
new Column() {
SelectAction = new SubmitAction() { Data = 1, Title = "Bad" },
Items = new List<CardElement>() { new Image() { Url = GeneralStrings.Feedback01 } }
}
}
});
var attachemnt = new Attachment() { ContentType = AdaptiveCard.ContentType, Content = card };
var message = context.MakeMessage();
message.Attachments.Add(attachemnt);
await context.PostAsync(message);
context.Wait<Activity>(this.AfterAskFeedback);

Related

Tabulator: How to create a dynamic custom editor based on another cell's value

Using Tabulator, I want to dynamically create a cell's editor, either input or select, based on another cell's value.
Declaring:
var valueEditor = function(cell, onRendered, success, cancel, editorParams)
I seem to be able to declare the correct editor and I have the list of values are available in the editorParams the is passed to the function API, but for theselect I can't get the drop-down to display the values.
Here's a code snippet:
var valueEditor = function(cell, onRendered, success, cancel, editorParams) {
const item = cell.getRow().getData();
var editor = null;
// Use a combobox when the type is Choice, or regular input cell otherwise
if (item.type === "Choice") {
editor = document.createElement("select");
editor.setAttribute("values", editorParams.values ); // <-- This is probably incorrect, but I'm unable to assign the right attribute
} else {
editor = document.createElement("input");
editor.setAttribute("type", "text");
}
//create and style input
editor.style.padding = "3px";
editor.style.width = "100%";
editor.style.boxSizing = "border-box";
editor.value = item.value;
//when the value has been set, trigger the cell to update
function successFunc(){
success(editor.value );
}
editor.addEventListener("change", successFunc);
editor.addEventListener("blur", successFunc);
//return the editor element
return editor;
};
{title: 'Name', field: 'name', width: 130},
{title: 'Type', field: 'type', width: 95},
{title: 'Value', field: 'value', width: 260, editor: valueEditor }];
When my row's type column is "Choice", I would like to show a combobox with, say Choice1, Choice2, Choice3, Choice4. Otherwise, I want to have a regular Input cell where the user can enter any values.
It took much time and I found this way to create custom select editor of Tabulator for showing NAME base on KEY value. Hope this post helps someone.
var cboData = [
{
"key": "",
"name": ""
},
{
"key": "01",
"name": "OPTION 1"
},
{
"key": "02",
"name": "OPTION 2"
}];
var comboEditor = function (cell, onRendered, success, cancel, editorParams) {
var editor = document.createElement("select");
for (var i = 0; i < editorParams.length; i++) {
var opt = document.createElement('option');
opt.value = editorParams[i].key;
opt.innerHTML = editorParams[i].name;
editor.appendChild(opt);
}
editor.style.padding = "3px";
editor.style.width = "100%";
editor.style.boxSizing = "border-box";
editor.value = cell.getValue();
onRendered(function () {
editor.focus();
editor.style.css = "100%";
});
function successFunc() {
success(editor.value);
}
editor.addEventListener("change", successFunc);
editor.addEventListener("blur", successFunc);
return editor;
};
In columns setting like this:
{
title: "SELECTION",
field: 'select_key',
headerHozAlign: 'center',
hozAlign: 'center',
editor: comboEditor,
editorParams: cboData,
formatter: function (cell, formatterParams) {
for (var i = 0; i < formatterParams.length; i++) {
if (formatterParams[i].key == cell.getValue()) {
return formatterParams[i].name;
}
}
},
formatterParams: cboData,
},
Edited:
If you want to load dropdown value based on another cell value, you can change as bellow:
var cboData = []; //Store last values based on another cell value
var comboEditor = function (cell, onRendered, success, cancel, editorParams) {
var editor = document.createElement("select");
//GET DATA FOR THIS HERE. NOTE THAT THIS CALL EVERY TIME YOU SELECT THIS DROPDOWN
let otherCellValue = cell.getData().OtherColName;
$.ajax({
type: 'POST',
url: [URL TO GET VALUE],
contentType: "application/json; charset=utf-8",
data: '{ key:' + JSON.stringify(otherCellValue ) + '}',
async: false, //wait ultil get data done
processData: false,
success: function (result) {
//assume that result is an array of data with VALUE/TEXT fields
for (var i = 0; i < result.length; i++) {
var item = {};
item.key = result[i].Value;
item.name = result[i].Text;
cboData.push(item);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
}
});
for (var i = 0; i < cboData.length; i++) {
var opt = document.createElement('option');
opt.value = cboData[i].key;
opt.innerHTML = cboData[i].name;
editor.appendChild(opt);
}
editor.style.padding = "3px";
editor.style.width = "100%";
editor.style.boxSizing = "border-box";
editor.value = cell.getValue();
onRendered(function () {
editor.focus();
editor.style.css = "100%";
});
function successFunc() {
success(editor.value);
}
editor.addEventListener("change", successFunc);
editor.addEventListener("blur", successFunc);
return editor;
};
item, I think, is an object, so you would need to find your property value for your cell, like :
editor.value = item[cell.getField()]

Adaptive Cards with QnAMaker using NodeJS

I’ve been learning NodeJS and have started to rebuild my Bot using v4 of the Bot Framework.
I have a Bot up and running in v3 using C# and it successfully uses a method where a QnA pairing is adapted into either a Hero Card, Video Card or standard reply depending on how many counts of a semi-colon the code finds.
I’m struggling to replicate this function in NodeJS using a string split method to determine what adaptive card should be used.
I’ve enclosed the original C# code and my partial attempt using NodeJS.
CSharp
protected override async Task RespondFromQnAMakerResultAsync(IDialogContext context, IMessageActivity message, QnAMakerResults result)
{
var answer = result.Answers.First().Answer;
Activity reply = ((Activity)context.Activity).CreateReply();
string[] qnaAnswerData = answer.Split(';');
int dataSize = qnaAnswerData.Length;
//image and video card
if (dataSize > 1 && dataSize <= 6)
{
var attachment = GetSelectedCard(answer);
reply.Attachments.Add(attachment);
await context.PostAsync(reply);
}
else
{
// await context.Forward(new BasicQnAMakerDialog(), AfterAnswerAsync, message, CancellationToken.None);
await context.PostAsync(answer);
}
}
private static Attachment GetSelectedCard(string answer)
{
int len = answer.Split(';').Length;
switch (len)
{
case 4: return GetHeroCard(answer);
case 6: return GetVideoCard(answer);
default: return GetHeroCard(answer);
}
}
private static Attachment GetHeroCard(string answer)
{
string[] qnaAnswerData = answer.Split(';');
string title = qnaAnswerData[0];
string description = qnaAnswerData[1];
string url = qnaAnswerData[2];
string imageURL = qnaAnswerData[3];
HeroCard card = null;
{
card = new HeroCard
{
Title = title,
Subtitle = description,
};
card.Buttons = new List<CardAction>
{
new CardAction(ActionTypes.OpenUrl, "Learn More", value: url)
};
card.Images = new List<CardImage>
{
new CardImage( url = imageURL)
};
}
return card.ToAttachment();
}
private static Attachment GetVideoCard(string answer)
{
string[] qnaAnswerData = answer.Split(';');
string title = qnaAnswerData[0];
string subtitle = qnaAnswerData[1];
string description = qnaAnswerData[2];
string thumbimageurl = qnaAnswerData[3];
string mediaUrl = qnaAnswerData[4];
string url = qnaAnswerData[5];
VideoCard card = new VideoCard
{
Title = title,
Subtitle = subtitle,
Text = description,
};
card.Image = new ThumbnailUrl
{
Url = thumbimageurl
};
card.Media = new List<MediaUrl>
{
new MediaUrl()
{
Url = mediaUrl
}
};
card.Buttons = new List<CardAction>
{
new CardAction()
{
Title = "View Full Screen",
Type = ActionTypes.OpenUrl,
Value = url
}
};
return card.ToAttachment();
}
Partial NodeJS
async onTurn(turnContext) {
if (turnContext.activity.type === ActivityTypes.Message) {
for (let i = 0; i < this.qnaServices.length; i++) {
// Perform a call to the QnA Maker service to retrieve matching Question and Answer pairs.
const qnaResults = await this.qnaServices[i].getAnswers(turnContext);
const qnaCard = qnaResults.includes(';');
// If an answer was received from QnA Maker, send the answer back to the user and exit.
if (qnaCard.toString().split(';').length > 3) {
await turnContext.sendActivity(qnaResults[0].answer);
await turnContext.sendActivity({
text: 'Video Card',
attachments: [CardFactory.adaptiveCard(VideoCard)]
});
} else if (qnaCard.toString().split(';').length < 3) {
await turnContext.sendActivity(qnaResults[0].answer);
await turnContext.sendActivity({
text: 'Hero Card',
attachments: [CardFactory.adaptiveCard(HeroCard)]
});
return;
}
}
The CardFactory in the v4 Node SDK has rendering functions for each type of card (HeroCards, VideoCards, AdaptiveCards, etc). You should use the corresponding function for the type of card you are trying to send. Your code should look like:
async onTurn(turnContext) {
if (turnContext.activity.type === ActivityTypes.Message) {
for (let i = 0; i < this.qnaServices.length; i++) {
// Perform a call to the QnA Maker service to retrieve matching Question and Answer pairs.
const qnaResults = await this.qnaServices[i].getAnswers(turnContext);
const qnaCard = qnaResults.includes(';');
// If an answer was received from QnA Maker, send the answer back to the user and exit.
if (qnaCard.toString().split(';').length > 3) {
await turnContext.sendActivity(qnaResults[0].answer);
await turnContext.sendActivity({
text: 'Video Card',
attachments: [CardFactory.videoCard(VideoCard)]
});
} else if (qnaCard.toString().split(';').length < 3) {
await turnContext.sendActivity(qnaResults[0].answer);
await turnContext.sendActivity({
text: 'Hero Card',
attachments: [CardFactory.heroCard(HeroCard)]
});
return;
}
}
}
}
Checkout the Using Cards and Using Adaptive Cards for more examples on how to send cards in the v4 BotFramework Node SDK.
Hope this helps!

Create Purchase receipt from Purchase order through web service

We are trying to create a PO receipt document that is linked to a PO document. Below is the code, but after submitting the selection of PO lines, the webservice not returning any results. Later it gives an execution time out exception.
apitest.Screen context = BuisnessLogicACU.context;
PO302000Content PORcptSchema;
try
{
PORcptSchema = context.PO302000GetSchema();
}
catch
{
BuisnessLogicACU.contextLogin();
PORcptSchema = context.PO302000GetSchema();
}
PORcptSchema.Actions.AddPOOrderLine2.Commit = true;
//header
AcumaticaInterface.apitest.Command[] Document = new AcumaticaInterface.apitest.Command[]
{
PORcptSchema.Actions.Insert,
new Value
{
Value = BPCode,
LinkedCommand = PORcptSchema.DocumentSummary.Vendor,
Commit = true
},
new Value
{
Value = BPRefNbr ,
LinkedCommand = PORcptSchema.DocumentSummary.VendorRef
},
new Value
{
Value = PostDate.HasValue ? ((DateTime)PostDate.Value).ToLongDateString() : "",
LinkedCommand = PORcptSchema.DocumentSummary.Date
},
new Value
{
Value = DocDate.HasValue ? ((DateTime)DocDate.Value).ToLongDateString() : "",
LinkedCommand = PORcptSchema.DocumentSummary.Date
},
new Value
{
Value = Description,
LinkedCommand = PORcptSchema.DocumentSummary.NoteText
},
new Value
{
Value = "POS Doc " + DocNum,
LinkedCommand = PORcptSchema.DocumentSummary.VendorRef
},
};
//set the dialog answer
var dgAnswer = new Command[]
{ new Value
{
Value = "OK",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.ServiceCommands.DialogAnswer,
Commit = true
}
};
Document = Document.Concat(dgAnswer).ToArray();
//select lines
foreach (POReceiptLine line in POReceiptlines.OrderBy(x => x.LineNum))
{
AcumaticaInterface.apitest.Command[] Docline = new AcumaticaInterface.apitest.Command[]
{
new Key
{
ObjectName = PORcptSchema.AddPurchaseOrderLine.OrderNbr.ObjectName,
FieldName = PORcptSchema.AddPurchaseOrderLine.OrderNbr.FieldName,
Value = "='" + line.BaseDocNum + "'"
},
new Key
{
ObjectName = PORcptSchema.AddPurchaseOrderLine.LineNbr.ObjectName,
FieldName = PORcptSchema.AddPurchaseOrderLine.LineNbr.FieldName,
Value = "='" + line.BaseLineNum + "'"
},
new Value
{
Value = "True",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.Selected,
Commit = true
}
};
Document = Document.Concat(Docline).ToArray();
}
//Add PO line.
var addPOLine = new Command[]
{
PORcptSchema.Actions.AddPOOrderLine2,
////get back the added lines in the grid
PORcptSchema.DocumentDetails.POOrderNbr,
PORcptSchema.DocumentDetails.POLineNbr
};
Document = Document.Concat(addPOLine).ToArray();
var receiptLines = context.PO302000Submit(Document);
//update quantity..
//check CreateShipment() in webservice demo
List<Command> commandList = new List<Command>();
for (int index = 0; index < receiptLines.Length; index++)
{
commandList.Add(new Value
{
Value = index.ToString(),
LinkedCommand = PORcptSchema.DocumentDetails.ServiceCommands.RowNumber
});
POReceiptLine line = POReceiptlines.Where(x => x.BaseDocNum == receiptLines[index].DocumentDetails.POOrderNbr.Value && x.BaseLineNum.ToString() == receiptLines[index].DocumentDetails.POLineNbr.Value).FirstOrDefault();
if (line != null)
{
commandList.Add(new Value
{
Value = line.Qty.ToString(),
LinkedCommand = PORcptSchema.DocumentDetails.ReceiptQty,
Commit = index < receiptLines.Length - 1
});
}
else
throw new Exception("Matching POS Rcpt line not found.");
}
//save
AcumaticaInterface.apitest.Command[] save = new AcumaticaInterface.apitest.Command[] {
PORcptSchema.Actions.Save
};
Document = Document.Concat(save).ToArray();
//SAVING And get the document nbr
AcumaticaInterface.apitest.Command[] Output = new AcumaticaInterface.apitest.Command[] {
PORcptSchema.DocumentSummary.Type,
PORcptSchema.DocumentSummary.ReceiptNbr
};
Document = Document.Concat(Output).ToArray();
var POReceipt = context.PO302000Submit(Document)[0];
After this particular line, web service is not returning any results. Anyone can assist on this?
var receiptLines = context.PO302000Submit(Document);
This solution was tested using Acumatica version 6.00.1596.
I found that to return the value of the Purchase Order Lines, you do not need to do a foreach.
After setting the value for the summary and removing the deuplicate here is what I use to get back the POLines.
var selectPOLine = new Command[]
{
new Value
{
Value = "OK",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.ServiceCommands.DialogAnswer,
Commit = true
},
addPOLineWithCommit,
new Value
{
LinkedCommand = PORcptSchema.AddPurchaseOrderLinePOSelection.OrderNbr,
Value = "PO000451"
},
new Value
{
Value = "True",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.Selected,
},
PORcptSchema.AddPurchaseOrderLine.InventoryID,
PORcptSchema.AddPurchaseOrderLine.LineDescription,
PORcptSchema.AddPurchaseOrderLine.LineType,
};
With "addPOLineWithCommit" define as
var addPOLineWithCommit = PORcptSchema.Actions.AddPOOrderLine;
addPOLineWithCommit.Commit = true;
Using these the line :
var receiptLines = context.PO302000Submit(Document);
was returning me some information on available lines.
#samol518's sample assisted me to resolve. I am posting the full code, if anyone later needs it
the below code will add lines from PO, change quantity and save the PO receipt.
public void createAcuPR()
{
apitest.Screen context = BuisnessLogicACU.context;
PO302000Content PORcptSchema;
try
{
PORcptSchema = context.PO302000GetSchema();
}
catch
{
BuisnessLogicACU.contextLogin();
PORcptSchema = context.PO302000GetSchema();
}
var addPOLineWithCommit = PORcptSchema.Actions.AddPOOrderLine;
addPOLineWithCommit.Commit = true;
//somehow if there is a second document then it goes to update mode
context.PO302000Submit(new Command[] { PORcptSchema.Actions.Insert });
//header
AcumaticaInterface.apitest.Command[] Document = new AcumaticaInterface.apitest.Command[]
{
PORcptSchema.Actions.Insert,
new Value
{
Value = BPCode,
LinkedCommand = PORcptSchema.DocumentSummary.Vendor,
Commit = true
},
new Value
{
Value = BPRefNbr ,
LinkedCommand = PORcptSchema.DocumentSummary.VendorRef
},
new Value
{
Value = PostDate.HasValue ? ((DateTime)PostDate.Value).ToLongDateString() : "",
LinkedCommand = PORcptSchema.DocumentSummary.Date
},
new Value
{
Value = "POS Doc " + DocNum + "-" + Description,
LinkedCommand = PORcptSchema.DocumentSummary.NoteText
}
};
//set the dialog answer
var dgAnswer = new Command[]
{ new Value
{
Value = "OK",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.ServiceCommands.DialogAnswer,
Commit = true
}
};
Document = Document.Concat(dgAnswer).ToArray();
//select lines from smart panel
foreach (POReceiptLine line in POReceiptlines.OrderBy(x => x.LineNum))
{
AcumaticaInterface.apitest.Command[] Docline = new AcumaticaInterface.apitest.Command[]
{
new Key
{
ObjectName = PORcptSchema.AddPurchaseOrderLine.OrderNbr.ObjectName,
FieldName = PORcptSchema.AddPurchaseOrderLine.OrderNbr.FieldName,
Value = "='" + line.BaseDocNum + "'"
},
new Key
{
ObjectName = PORcptSchema.AddPurchaseOrderLine.LineNbr.ObjectName,
FieldName = PORcptSchema.AddPurchaseOrderLine.LineNbr.FieldName,
Value = "='" + line.BaseLineNum + "'"
},
new Value
{
Value = "True",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.Selected,
Commit = true
}
};
Document = Document.Concat(Docline).ToArray();
}
//Add PO line and retrive back the added lines.
var addPOLine = new Command[]
{
addPOLineWithCommit,
////get back the added lines in the grid
PORcptSchema.DocumentDetails.POOrderNbr,
PORcptSchema.DocumentDetails.POLineNbr
};
Document = Document.Concat(addPOLine).ToArray();
var receiptLines = context.PO302000Submit(Document);
//update quantity..
List<Command> commandList = new List<Command>();
for (int index = 0; index < receiptLines.Length; index++)
{
commandList.Add(new Value
{
Value = index.ToString(),
LinkedCommand = PORcptSchema.DocumentDetails.ServiceCommands.RowNumber
});
POReceiptLine line = POReceiptlines.Where(x => x.BaseDocNum == receiptLines[index].DocumentDetails.POOrderNbr.Value && x.BaseLineNum.ToString() == receiptLines[index].DocumentDetails.POLineNbr.Value).FirstOrDefault();
if (line != null)
{
commandList.Add(new Value
{
Value = line.Qty.ToString(),
LinkedCommand = PORcptSchema.DocumentDetails.ReceiptQty,
Commit = index < receiptLines.Length - 1
});
}
else
throw new Exception("Matching POS Rcpt line not found.");
}
//save
commandList.AddRange(
//SAVING And get the document nbr
new AcumaticaInterface.apitest.Command[] {
PORcptSchema.Actions.Save,
PORcptSchema.DocumentSummary.Type,
PORcptSchema.DocumentSummary.ReceiptNbr
});
var POReceipt = context.PO302000Submit(commandList.ToArray())[0];
}
This code is working, Receipt is creating but new created receipt is not generated for newley generated Purchase order, this receipt is generated for old any PO

Updating existing activity with attachments

I need to update an attachment to an existing activity using Web API from my application to an existing case in Acumatica Partner's Portal.
I have already written a code to this but it is updating to first activity always instead of for the activity I am passing the noteid.
I am doing this by retrieving the noteid of the activity created and then sending the same noteid along with caseid to update an attachment.
Below is the code which is updating the existing activity with attachment, please suggest.
var origActivities = context1.Export
(
new SP203010WS.Command[]
{
new SP203010WS.Value
{
Value = currentAcumaticaCaseNo,
LinkedCommand = content.Case.CaseID
},
content.Activities.Type,
content.Activities.Summary,
new SP203010WS.Field
{
FieldName = "NoteID",
ObjectName = content.Activities.Summary.ObjectName
},
content.Activities.CreatedAt,
},
null, 0, false, false
);
Guid?[] origActivityNoteID = null;
DateTime?[] origActivityCreatedDate = null;
if (origActivities != null && origActivities.Count() > 0)
{
origActivityNoteID = new Guid?[origActivities.Count()];
origActivityCreatedDate = new DateTime?[origActivities.Count()];
int i = 0;
foreach (string[] activity in origActivities)
{
origActivityNoteID[i] = new Guid(activity[2].ToString());
origActivityCreatedDate[i] = Convert.ToDateTime(activity[3]);
i++;
}
}
*****Adding new activity*****
var newActivities = context.Export
(
new SP203010WS.Command[]
{
new SP203010WS.Value
{
Value = currentAcumaticaCaseNo,
LinkedCommand = content.Case.CaseID
},
content.Activities.Type,
content.Activities.Summary,
new SP203010WS.Field
{
FieldName = "NoteID",
ObjectName = content.Activities.Summary.ObjectName
},
content.Activities.CreatedAt,
},
null, 0, false, false
);
Guid? newActivityNoteID = null;
for (var i = 1; i <= newActivities.GetUpperBound(0); i++)
{
if(origActivityNoteID != null && origActivityCreatedDate != null)
{
if((Array.IndexOf<Guid?>(origActivityNoteID, new Guid(newActivities[i][2])) <= 0) &&
(Array.IndexOf<DateTime?>(origActivityCreatedDate, Convert.ToDateTime(newActivities[i][3])) <= 0))
{
newActivityNoteID = new Guid(newActivities[i][2]);
break;
}
}
}
*****getting a list of all attachments*****
foreach (FileInfo fi in fileInfo)
{
SP203010WS.Content[] content1 = context.Submit
(
new SP203010WS.Command[]
{
new SP203010WS.Value
{
//Value = actiPartner.AcumaticaCaseID,
Value = currentAcumaticaCaseNo,
LinkedCommand = CR306000.Case.CaseID
},
new SP203010WS.Value
{
Value = newActivityNoteID.ToString(),
LinkedCommand = new SP203010WS.Field { FieldName="NoteID", ObjectName="Activities" }
},
new SP203010WS.Value
{
FieldName = fi.Name,
Value = Convert.ToBase64String(fi.BinData),
LinkedCommand = CR306000.Activities.ServiceCommands.Attachment
},
CR306000.Actions.Save
}
);
}
Looks like search in Screen-Based API has no support for GUIDs. You will have to locate necessary Attachment by other fields values, for instance: Type, Summary and CreatedAt:
Screen context = new Screen();
context.CookieContainer = new System.Net.CookieContainer();
context.Url = "http://localhost/ActivityAttachments/Soap/CR306000.asmx";
context.Login("admin", "123");
var content = context.GetSchema();
var newActivities = context.Export
(
new Command[]
{
new Value
{
Value = "000110",
LinkedCommand = content.CaseSummary.CaseID
},
content.Activities.Type,
content.Activities.Summary,
content.Activities.CreatedAt,
},
null, 0, false, false
);
byte[] filedata;
using (FileStream file = File.Open("EP507011.txt", FileMode.Open))
{
filedata = new byte[file.Length];
file.Read(filedata, 0, filedata.Length);
}
Content[] content1 = context.Submit
(
new Command[]
{
new Value
{
Value = "000110",
LinkedCommand = content.CaseSummary.CaseID
},
new Key
{
ObjectName = content.Activities.Type.ObjectName,
FieldName = content.Activities.Type.FieldName,
Value = string.Format("='{0}'", newActivities[newActivities.Length - 2][0])
},
new Key
{
ObjectName = content.Activities.Summary.ObjectName,
FieldName = content.Activities.Summary.FieldName,
Value = string.Format("='{0}'", newActivities[newActivities.Length - 2][1])
},
new Key
{
ObjectName = content.Activities.CreatedAt.ObjectName,
FieldName = content.Activities.CreatedAt.FieldName,
Value = newActivities[newActivities.Length - 2][2]
},
new Value
{
FieldName = "EP507011.txt",
Value = Convert.ToBase64String(filedata),
LinkedCommand = content.Activities.ServiceCommands.Attachment
},
content.Actions.Save
}
);

MVC5 Identity Seed Users in database

I am getting an error that says: "UserId not found." when trying to seed multiple users into my database.
Here is my seed method:
protected override void Seed(newBestPlay.Models.ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
InitialCreate create = new InitialCreate();
create.Down();
create.Up();
context.Configuration.LazyLoadingEnabled = true;
if (!context.Roles.Any(r => r.Name == "Admin"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "Admin" };
manager.Create(role);
}
if (!context.Roles.Any(r => r.Name == "User"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "User" };
manager.Create(role);
}
if (!context.Users.Any(u => u.UserName == "user1"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser { UserName = "user1", Email = "email1" };
manager.Create(user, "ChangeItAsap!");
manager.AddToRole(user.Id, "Admin");
}
if (!context.Users.Any(u => u.UserName == "user2"))
{
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser { UserName = "user2", Email = "email2" };
manager.Create(user, "ChangeItAsap!");
manager.AddToRole(user.Id, "Admin");
}
}
It is failing on that last "manager.AddToRole" line. I figured out the second user isn't even getting added to the database, so it can't find a user.Id since it never got added.
Figured it out. It was not allowing dashes in my username. My username(email) has a dash in the domain part. I had to add in
this.UserValidator = new UserValidator<ApplicationUser>(this) { AllowOnlyAlphanumericUserNames = false };
into my IdentityConfig.cs file into the ApplicationUserManager constructor so it now looks like this:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
this.UserValidator = new UserValidator<ApplicationUser>(this) { AllowOnlyAlphanumericUserNames = false };
}
.....
add this into your seed method:
var manager = new UserManager<ApplicationUser>(store);
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
};

Resources