我最近一直在将我的代码重新分解为从inproc转移到Session State。我创建了一个新的类,我从一开始就构建了可序列化的类。我目前正在收到“无法序列化会话状态”。错误。但是,我能够使用JsonConvert(newtonsoft)序列化该类。
不允许使用哪种方法?
这就是它的样子:
[Serializable()]
public class SessionStateObject
{
public int CurrentSessionId { get; set; }
public int CurrentAssessmentId { get; set; }
public int CurrentAssessmentElementId { get; set; }
public int CurrentUserId { get; set; }
public Dictionary<string, int> AssessmentItemsIds { get; set; }
public Dictionary<string, int> SessionResponseIds { get; set; }
public List<string> AdministeredItemOrderByName;
public string LastVisitedItem;
public int? TotalAssessmentCurrentItemOrder;
public RenderablePersistanceObject RenderablePersistance;
#region formula engine section variables
public string BranchingResult { get; set; }
public string ContentOutput { get; set; }
public int CurrentItemId { get; set; }
public int VirtualWorkingItemId { get; set; }
public bool isCloneItem { get; set; }
public bool wasPreFormulaRun;
public bool wasContentOutput;
public bool wasPrefillReached;
public bool isVirtual;
public List<string> FormulaStack { get; set; }
public List<string> ItemNameTokens { get; set; }
public string serializedJSContext { get; set; }
public string CloneSourceItem { get; set; }
public int itemsAbletoFastForwardThrough { get; set; }
#endregion
private Dictionary<int, int> itemIdByMultiGroupId; //key is itemId, val is groupId
private Dictionary<int, List<int>> MultiGroupIdByItemIds; //key is groupId, val is itemId
public SessionStateObject()
{
RenderablePersistance = new RenderablePersistanceObject();
AssessmentItemsIds = new Dictionary<string, int>();
SessionResponseIds = new Dictionary<string, int>();
AdministeredItemOrderByName = new List<string>();
FormulaStack = new List<string>();
ItemNameTokens = new List<string>();
itemIdByMultiGroupId = new Dictionary<int, int>();
MultiGroupIdByItemIds = new Dictionary<int, List<int>>();
}
public void initMultiItemGroups(Assessment assessment, NetScidDbContainer dbContext)
{
List<MultiItem> assessmentMultiItems = (from multi in dbContext.MultiItems
where multi.AssessmentId == assessment.Id
select multi).ToList();
List<int> uniqueGroupIds = new List<int>();
foreach (MultiItem mItem in assessmentMultiItems)
{
itemIdByMultiGroupId.Add(mItem.ItemId, mItem.GroupId);
if (!uniqueGroupIds.Contains(mItem.GroupId))
{
uniqueGroupIds.Add(mItem.GroupId);
}
}
foreach (int groupId in uniqueGroupIds)
{
List<int> ItemIds = (from itemGroup in assessmentMultiItems
where itemGroup.GroupId == groupId
orderby itemGroup.Id ascending
select itemGroup.ItemId).ToList();
MultiGroupIdByItemIds.Add(groupId, ItemIds);
}
}
public List<int> GetItemIdsFromSingleItemId(int itemId)
{
List<int> foundItemIDs = new List<int>();
int foundGroupId = -1;
if (this.itemIdByMultiGroupId.ContainsKey(itemId))
{
foundGroupId = this.itemIdByMultiGroupId[itemId];
}
if (this.MultiGroupIdByItemIds.ContainsKey(foundGroupId))
{
foundItemIDs = this.MultiGroupIdByItemIds[foundGroupId];
}
return foundItemIDs;
}
public void nullifyRenderable()
{
this.RenderablePersistance = null;
}
public void PersistRenderable(IRenderable renderable)
{
this.RenderablePersistance = new RenderablePersistanceObject();
if (renderable is MultiItemRenderable)
{
//get list of item IDs from the multi-item lookup
this.RenderablePersistance.isMultiItem = true;
this.RenderablePersistance.primaryItemId = ((Item)((MultiItemRenderable)renderable).IndexedItems.Last()).Id;
}
else //regular renderable
{
this.RenderablePersistance.isMultiItem = false;
this.RenderablePersistance.primaryItemId = ((Item)renderable).Id;
}
}
public AssessmentRuntime StartAdministrativeSession(NetScidDbContainer dataContext, Assessment assessment, User currentUser, string pid = "1")
{
AssessmentRuntime newRuntime = new AssessmentRuntime(this, dataContext);
Session newSession = new Session();
assessment.PrepElements();
PermissionEntity rootPE = new PermissionEntity();
if (currentUser != null)
{
rootPE = PermissionEntityHelper.GetRootPermissionEnity(dataContext, currentUser);
}
else
{
rootPE = (from adminpe in dataContext.PermissionEntities
where adminpe.Name == "TelesageAdmin"
select adminpe
).FirstOrDefault();
}
newSession.Participant = (from pids in dataContext.ParticipantIdAliasLookups
where pid == pids.AliasId && pids.RootPermissionEntity.Id == rootPE.Id
select pids.Participant).FirstOrDefault();
if (newSession.Participant == null)
{
Participant newParticipant = new Participant();
ParticipantIdAliasLookup newPidAlias = new ParticipantIdAliasLookup();
newParticipant.ParticipantDataJSON = "";
newPidAlias.AliasId = pid;
newPidAlias.RootPermissionEntity = rootPE;
newParticipant.AliasLookup = newPidAlias;
newParticipant.PermissionEntities.Add(currentUser.PermissionEntity);
newParticipant.PermissionEntities.Add(rootPE);
newSession.Participant = newParticipant;
dataContext.Participants.AddObject(newParticipant);
dataContext.ParticipantIdAliasLookups.AddObject(newPidAlias);
}
newSession.Assessment = assessment;
newSession.User = currentUser;
newSession.StartTime = DateTime.Now;
newSession.PermissionEntity = currentUser.PermissionEntity;
newSession.SetSessionData("engineversion", typeof(SmartQWeb.MvcApplication).Assembly.GetName().Version.ToString());
newSession.SetSessionData("assessmentname", newSession.Assessment.Name);
newSession.SetSessionData("assessmentversion", newSession.Assessment.Version);
newSession.SetSessionData("computername", Environment.MachineName);
newSession.SetSessionData("username", currentUser.Name);
dataContext.Sessions.AddObject(newSession);
newSession.SetSessionData("dxdata", JsonConvert.SerializeObject(newRuntime.RenderedDiagnoses));
newRuntime.formulaEngine = new FixedLengthFormulaEngine(newRuntime);
SessionLog newSessionLog = new SessionLog();
dataContext.SessionLogs.AddObject(newSessionLog);
newSession.SessionLog = newSessionLog;
dataContext.SaveChanges();
initMultiItemGroups(assessment, dataContext);
this.CurrentSessionId = newSession.Id;
this.CurrentUserId = currentUser.Id;
this.CurrentAssessmentId = assessment.Id;
newRuntime.Context = new RuntimeContext(this, dataContext);
this.GetAssessmentItems(assessment); //to populate the items dict
newRuntime.formulaEngine.InitializeContext(this.AssessmentItemsIds.Keys.ToList());
newRuntime.RenderedDiagnoses = new RenderedDiagnosisModel(newRuntime.Context.AdministeredItemOrderByName);
newRuntime.Context.Logger.WriteLog("Session started with assessment: " + newRuntime.Context.Assessment.Name + " with version: " + newRuntime.Context.Assessment.Version);
newRuntime.Context.Logger.WriteLog("Session started by user: " + newRuntime.Context.CurrentUser.Name + "for participant ID: " + newSession.ParticipantId);
return newRuntime;
}
//start from a previous existing session
public AssessmentRuntime StartAdministrativeSession(NetScidDbContainer dataContext, Assessment assessment, Session previousSession, User currentUser, string pid = "", string resumefromlatest = "false")
{
AssessmentRuntime newRuntime = new AssessmentRuntime(this, dataContext);
Session newSession = new Session();
Assessment sessionAssessment = assessment;
newSession.ParticipantId = previousSession.ParticipantId;
//THE OTHER ENTITIES BESIDES THE SESSION NEED TO BE DETATCHED AND RE-ATTACHED (BY BEING ADDED TO THE NEW SESSION)
assessment.PrepElements();
newRuntime.RenderedDiagnoses = new RenderedDiagnosisModel(newRuntime.Context.AdministeredItemOrderByName);
List<Response> prevresponses = previousSession.Responses.ToList();
if (sessionAssessment == assessment)
{
foreach (Response prevresponse in prevresponses)
{
newRuntime.Context.CachedAssessmentResponses.Add(prevresponse.Item.ItemName, prevresponse);
dataContext.Detach(prevresponse);
newSession.Responses.Add(prevresponse);
}
}
else
{
//the sessionAssessment is now the more up-to-date one so the responses pulled will have to be mapped, not just detatched and copied
foreach (Response prevresponse in prevresponses)
{
Dictionary<string, FixedLengthItem> newAssessmentItemNames = AssessmentHelper.GetAssessmentItems(sessionAssessment);
if (!newAssessmentItemNames.ContainsKey(prevresponse.Item.ItemName))
continue;
Response newResponse = new Response
{
NumericValue = prevresponse.NumericValue,
Item = newAssessmentItemNames[prevresponse.Item.ItemName],
ItemName = prevresponse.Item.ItemName,
AdministeredOrder = -1,
Value = prevresponse.Value
};
newRuntime.Context.CachedAssessmentResponses.Add(newResponse.Item.ItemName, newResponse);
newSession.Responses.Add(newResponse);
}
}
newSession.SessionDataJSON = previousSession.SessionDataJSON;
//DxData
newRuntime.RenderedDiagnoses =
JsonConvert.DeserializeObject<RenderedDiagnosisModel>(newSession.GetSessionData("dxdata"));
//inc session is =2 when the the session has been resumed by
previousSession.IncSession = 2;
newSession.SetSessionData("previoussession", previousSession.Id.ToString());
newSession.Participant = previousSession.Participant;
newSession.Assessment = sessionAssessment;
newSession.User = currentUser;
newSession.PermissionEntity = currentUser.PermissionEntity;
newSession.StartTime = DateTime.Now;
dataContext.Sessions.AddObject(newSession);
dataContext.SaveChanges();
newRuntime.formulaEngine = new FixedLengthFormulaEngine(newRuntime);
initMultiItemGroups(assessment, dataContext);
newSession.SetSessionData("continuedsession", newSession.Id.ToString());
this.CurrentSessionId = newSession.Id;
this.CurrentUserId = currentUser.Id;
this.CurrentAssessmentId = assessment.Id;
this.GetAssessmentItems(assessment); //to populate the items dict
this.SetUpPreviousResponses(newSession); //populates SSO responses
newRuntime.Context = new RuntimeContext(this, dataContext);
if (newRuntime.RenderedDiagnoses != null)
newRuntime.RenderedDiagnoses.reInitAdminOrder(newRuntime.Context.AdministeredItemOrderByName);
newRuntime.formulaEngine.InitializeContext(this.AssessmentItemsIds.Keys.ToList());
return newRuntime;
}
//start from the SSO
public AssessmentRuntime ResumeSessionFromState(NetScidDbContainer dataContext)
{
AssessmentRuntime newRuntime = new AssessmentRuntime(this, dataContext);
newRuntime.formulaEngine = new FixedLengthFormulaEngine(newRuntime);
newRuntime.formulaEngine.InitializeSerializedContext(serializedJSContext);
newRuntime.Context = new RuntimeContext(this, dataContext);
if (this.CurrentAssessmentElementId != 0)
{
newRuntime.CurrentAssessmentElement = (from ae in dataContext.AssessmentElements
where ae.Id == this.CurrentAssessmentElementId
select ae).FirstOrDefault();
newRuntime.CurrentAssessmentElement.GetNewRuntime(newRuntime.Context);
}
return newRuntime;
}
private void GetAssessmentItems(Assessment assessment)
{
var fixedLengthElements = (from elements in assessment.AssessmentElements
where elements is FixedLengthBlock
select elements);
foreach (FixedLengthBlock elemblock in fixedLengthElements)
{
foreach (FixedLengthItem item in elemblock.ItemBank.Items)
{
item.aeRef = elemblock;
AssessmentItemsIds.Add(item.ItemName, item.Id);
}
}
}
private void SetUpPreviousResponses(Session newSession)
{
//put response IDs by itemname into this dictionary
SessionResponseIds = (from response in newSession.Responses
select response).ToDictionary(key => key.ItemName, value => value.Id);
}
}
RenderablePersistanceObject如下所示:
public class RenderablePersistanceObject
{
public int primaryItemId;
public int MultiItemGroupId;
public bool isMultiItem;
}
答案 0 :(得分:0)
您不能像这样序列化直字典。您可以查看此MSDN文章,了解有关实施的建议。如果你真的不需要一个词典,也许List&gt;可能会更好吗?
答案 1 :(得分:0)
正如Erik指出的那样,导致问题的另一个对象缺乏装配[Serializable()]。添加它解决了我的问题。