I am currently trying to create a list of custom objects using data I get back from isolatedstorage, and deserializing it.
it worked perfectly yesterday and just keeps givin me this exception today, and I am not sure what to do?
{System.ArgumentOutOfRangeException: Length cannot be less than zero.
Parameter name: length
at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length, Boolean fAlwaysCopy)
at System.String.Substring(Int32 startIndex, Int32 length)
at LandbouWP.ViewModel.StoryVM.GetStories(List`1 news_items)}
the code for getting the data and deserializing it:
var loaded_result = settings["mainlist"].ToString();
var s = JsonConvert.DeserializeObject<List<Object>>(loaded_result);
the deserializing works perfectly, so I don't think the issue is here, however does it maybe add another property or something to the list?
then I create a custom list of the returned items
App.StoryViewModel.GetStories(s);
and that code is:
public void GetStories(List<Object> news_items)
{
List<Story> a = new List<Story>();
List<Story> b = new List<Story>();
//loop over all items and add them for a viewmodel
int i = 0;
foreach (var item in news_items)
{
if (item.IsDeleted == true)
{
//do not add the item
}
else
{
try
{
a.Add(new Story
{
ID = news_items[i].ID,
IsDeleted = news_items[i].IsDeleted,
IsActive = news_items[i].IsActive,
Title = news_items[i].Title,
Author = news_items[i].Author,
Synopsis = news_items[i].Synopsis,
Body = news_items[i].Body,
ImageUrl = news_items[i].ImageUrl,
//CreationDate = DateTime.Parse(news_items[i].CreationDate),
CreationDate = news_items[i].CreationDate.Substring(0, news_items[i].CreationDate.IndexOf('T')),
LastUpdateDate = news_items[i].LastUpdateDate.Substring(0, news_items[i].LastUpdateDate.IndexOf('T')),
DisplayUntilDate = news_items[i].DisplayUntilDate.Substring(0, news_items[i].DisplayUntilDate.IndexOf('T')),
TotalViews = news_items[i].TotalViews,
Gallery = news_items[i].Gallery
});
i++;
}
catch (Exception ex)
{
string msg = ex.ToString();
string msg2 = msg;
}
}
}
//try here to remove duplicates?
foreach (var item in a)
{
if (!b.Contains(item))
{
b.Add(item);
}
else
{
b.Remove(item);
}
}
var new_list = b.OrderByDescending(x => x.CreationDate).ToList();
//save all the stories
story = new_list;
I cannot even go through each item individually that I am trying to set, it just throws length cannot be less than zero, and I am not sure what its talking about, I do not have a parameter in my class named Length?
Check carefully this place
CreationDate = news_items[i].CreationDate.Substring(0, news_items[i].CreationDate.IndexOf('T')),
LastUpdateDate = news_items[i].LastUpdateDate.Substring(0, news_items[i].LastUpdateDate.IndexOf('T')),
DisplayUntilDate = news_items[i].DisplayUntilDate.Substring(0, news_items[i].DisplayUntilDate.IndexOf('T')),
I suppose one of your dates just in wrong format and has no "T"
Related
Essentially what the title says, for whatever reason when I call clientContext.ExecuteQuery(); and for example the list the data is going into has a missing column, I don't get an exception, it actually just runs as expected and I have to go and investigate what might have caused the data to not appear.
The NuGet package i'm using is Microsoft.SharePoint2016.CSOM version 16.0.4690.1000
Any hints, or suggestions to point me in the right direction appreciated. It's entirely possible I'm being a bit dim here.
Here's the full code block I'm using for updating list items:
public override object UpdateEntity(object entity)
{
if (entity == null)
{
// if the definition is null throw argument null exception.
throw new ArgumentNullException(nameof(SharePointDefinition));
}
// check for incorrect type being passed in that we can still handle
if (entity is List<SharePointDefinition> definitions)
{
return UpdateEntities(definitions);
}
ExceptionHandlingScope exceptionScopeFetch = new ExceptionHandlingScope(clientContext);
ExceptionHandlingScope exceptionScopeSubmit = new ExceptionHandlingScope(clientContext);
// run single definition submit to SP.
if (entity is SharePointDefinition definition)
{
// variables.
IntegrationEventLog log = new IntegrationEventLog();
EventInformation ei = new EventInformation();
List list = null;
ListItemCollection listItemCol = null;
using (exceptionScopeFetch.StartScope())
{
using (exceptionScopeFetch.StartTry())
{
// get the required list
list = clientContext.Web.Lists.GetByTitle(definition.ListName);
// create query
listItemCol = list.GetItems(CamlQuery.CreateAllItemsQuery());
// set these items for retrieval.
clientContext.Load(listItemCol);
}
using (exceptionScopeFetch.StartCatch())
{
// Assume that if there's an exception, it can only be
// because there is no list with the specified title, so report this back.
if (exceptionScopeFetch.HasException)
{
ei = new EventInformation()
{
LoggingEventType = LoggingEventType.DataSentFailure,
LoggingSeverity = LoggingSeverity.HighSeverity,
SerialisedMessage = JsonConvert.SerializeObject(definition),
ServiceMessage = $"Hit SharePoint exception handler during list and data pull: Message: {exceptionScopeFetch.ErrorMessage}",
StackTrace = exceptionScopeFetch.ServerStackTrace,
TimeGenerated = DateTime.Now,
TimeWritten = DateTime.Now,
};
log.EventLogEntryType = EventLogEntryType.Error;
log.EventID = LoggingSeverity.HighSeverity;
log.Message = JsonConvert.SerializeObject(ei);
AddToLog(log);
}
}
using (exceptionScopeFetch.StartFinally())
{
//
}
}
// get item instances first
try
{
clientContext.ExecuteQuery();
}
catch (Exception genEx)
{
// return failure log.
ei = new EventInformation()
{
LoggingEventType = LoggingEventType.DataSentFailure,
LoggingSeverity = LoggingSeverity.HighSeverity,
SerialisedMessage = JsonConvert.SerializeObject(definition),
ServiceMessage = "Errored trying to get data from SharePoint list ready for update operation; see stacktrace for more information.",
StackTrace = genEx.StackTrace,
TimeGenerated = DateTime.Now,
TimeWritten = DateTime.Now,
};
log.EventLogEntryType = EventLogEntryType.Error;
log.EventID = LoggingSeverity.HighSeverity;
log.Message = JsonConvert.SerializeObject(ei);
AddToLog(log);
return false;
}
// this is the column we want to overwrite.
var comparisonColumn = definition.UpdateIdentifier ?? "";
//List col to dict
var listItems = listItemCol.Cast<ListItem>().ToList();
// Now we know if we were able to retrieve existing data, perform submit.
using (exceptionScopeSubmit.StartScope())
{
using (exceptionScopeSubmit.StartTry())
{
// loop through our rows
foreach (var row in definition.RowData)
{
int existingItemIndex = -1;
// see if the row exists already
if (!string.IsNullOrEmpty(comparisonColumn) && listItems.Count != 0)
{
existingItemIndex = listItems.FindIndex(x => x[comparisonColumn].ToString() == row[comparisonColumn]);
}
if (existingItemIndex != -1 && listItems.Count != 0)
{
// item exists - loop through our row columns
foreach (var keyValuePair in row)
{
// they key relates to a column, the Value to the rows colum Value.
listItems[existingItemIndex].ParseAndSetFieldValue(keyValuePair.Key, keyValuePair.Value);
}
// update this item
listItems[existingItemIndex].Update();
}
else
{
ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
ListItem newItem = list.AddItem(itemCreateInfo);
// loop through our row columns
foreach (var keyValuePair in row)
{
// they key relates to a column, the Value to the rows colum Value.
newItem[keyValuePair.Key] = keyValuePair.Value;
}
newItem.Update();
}
}
}
using (exceptionScopeSubmit.StartCatch())
{
// Assume that if there's an exception, it can only be
// because there is no list with the specified title, so report this back.
if (exceptionScopeFetch.HasException)
{
ei = new EventInformation()
{
LoggingEventType = LoggingEventType.DataSentFailure,
LoggingSeverity = LoggingSeverity.HighSeverity,
SerialisedMessage = JsonConvert.SerializeObject(definition),
ServiceMessage = $"Error at SharePoint exception handler during submit to list: Message: {exceptionScopeFetch.ErrorMessage}",
StackTrace = exceptionScopeFetch.ServerStackTrace,
TimeGenerated = DateTime.Now,
TimeWritten = DateTime.Now,
};
log.EventLogEntryType = EventLogEntryType.Error;
log.EventID = LoggingSeverity.HighSeverity;
log.Message = JsonConvert.SerializeObject(ei);
AddToLog(log);
}
}
using (exceptionScopeSubmit.StartFinally())
{
//
}
}
// try to execute submit.
try
{
clientContext.ExecuteQuery();
ei = new EventInformation()
{
LoggingEventType = LoggingEventType.DataSentSuccess,
LoggingSeverity = LoggingSeverity.Information,
SerialisedMessage = JsonConvert.SerializeObject(definition),
ServiceMessage = "No exceptions were thrown from the Execution process.",
StackTrace = "",
TimeGenerated = DateTime.Now,
TimeWritten = DateTime.Now,
};
log.EventLogEntryType = EventLogEntryType.Information;
log.EventID = LoggingSeverity.Information;
log.Message = JsonConvert.SerializeObject(ei);
}
catch (Exception genEx)
{
ei = new EventInformation()
{
LoggingEventType = LoggingEventType.DataSentFailure,
LoggingSeverity = LoggingSeverity.HighSeverity,
SerialisedMessage = JsonConvert.SerializeObject(definition),
ServiceMessage = $"Data failed to be updated within SharePoint - {genEx.Message} - see stacktrace for more information.",
StackTrace = genEx.StackTrace,
TimeGenerated = DateTime.Now,
TimeWritten = DateTime.Now,
};
log.EventLogEntryType = EventLogEntryType.Error;
log.EventID = LoggingSeverity.HighSeverity;
log.Message = JsonConvert.SerializeObject(ei);
AddToLog(log);
return false;
}
AddToLog(log);
return true;
}
else
{
// If a different definition type is passed in throw an appropriate exception.
// This should be caught at runtime only.
throw new TypeLoadException(nameof(SharePointDefinition));
}
}
I checked the code you posted and I see that you are updating the list of objects, in your case listItems, instead of a ListItem in ListItemCollection, in your case listItemCol.
To be more clear, I believe you can try to replace listItems with listItemCol.
For instance, instead of:
listItems[existingItemIndex].ParseAndSetFieldValue(keyValuePair.Key, keyValuePair.Value);
use
listItemCol[existingItemIndex][keyValuePair.Key] = keyValuePair.Value;
So I went away and re-read a lot of documentation and looked over some examples, and I wondered why the exception handler never returned errors even though it's obvious there were issues with the query being executed. If you look at the Microsoft documentation and their example here you'll see that they don't show you how to use exceptionScopeSubmit.HasException component of the exception scope object. Which lead to a really stupid assumption on my part. It turns out that the exception block runs on the SharePoint server and should be used to fix issues you might have caused during an expected exception in your query.
Not only that but wrapping the ExecuteQuery in the try catch is redundant when using an exception scope as it means that method will no longer throw an exception. You actually have to assess exceptionScopeSubmit.HasException after the execution to pull back some more detailing information on errors reported by the SharePoint server side execution of your query.
So now I'm using it as below, and I can get detailed error information without having to do some stupid manual debugging which would easily take me hours to track down silly issues. So in case anyone stumbles across this having the same issues, I hope it helps.
ExceptionHandlingScope exceptionScopeFetch = new ExceptionHandlingScope(clientContext);
// variables.
IntegrationEventLog log = new IntegrationEventLog();
EventInformation ei = new EventInformation();
List list = null;
ListItemCollection listItemCol = null;
using (exceptionScopeFetch.StartScope())
{
using (exceptionScopeFetch.StartTry())
{
// get the required list
list = clientContext.Web.Lists.GetByTitle(definition.ListName);
// create query
listItemCol = list.GetItems(CamlQuery.CreateAllItemsQuery());
// set these items for retrieval.
clientContext.Load(listItemCol);
}
using (exceptionScopeFetch.StartCatch())
{
//
}
using (exceptionScopeFetch.StartFinally())
{
//
}
}
// get item instances first
clientContext.ExecuteQuery();
if (exceptionScopeSubmit.HasException)
{
ei = new EventInformation()
{
LoggingEventType = LoggingEventType.DataSentFailure,
LoggingSeverity = LoggingSeverity.HighSeverity,
SerialisedMessage = JsonConvert.SerializeObject(definition),
ServiceMessage = $"Error at SharePoint exception handler during submit to list: Message: {exceptionScopeFetch.ErrorMessage}",
StackTrace = exceptionScopeFetch.ServerStackTrace,
TimeGenerated = DateTime.Now,
TimeWritten = DateTime.Now,
};
log.EventLogEntryType = EventLogEntryType.Error;
log.EventID = LoggingSeverity.HighSeverity;
log.Message = JsonConvert.SerializeObject(ei);
AddToLog(log);
}
What I am trying to achieve is that I have a file "Additional courses" that has some format error and duplication error. When I import that file into my Course object array, it should catch those errors. I am stuck at how to check for those errors and also I have a problem while importing.
Can someone look at both of those errors please?
public void ImportCourses(string fileName, char Delim)
{
FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StreamReader reader = new StreamReader(stream);
int index = 0;
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var array = line.Split(Delim);
Course C = new Course();
C.CourseCode = array[0];
C.Name = array[1];
C.Description = array[2];
C.NoOfEvaluations = int.Parse(array[3]);
courses[index++] = C;
//Console.WriteLine(C.GetInfo());
}
reader.Close();
stream.Close();
These are the exceptions I want to check for:
If number of fields is incorrect the message is “Invalid number of fields in record {record number}”
If course code is already used in the course collection the message is “Course code in record {record number} is in use”
If the number of evaluation is not a number the message is “Number of evaluations in record {record number} is not in correct format.
I am getting "index out of bounds array" exception and I don't know where to start with the exception.
This is my .txt I am Trying to Import:
You should check the array.Length to make sure that you have 4 elements before you try to access them. If the split fails because the data was was empty or the data did not have 4 delimiters, then the array will not be 4 elements long and attempt to access an element by index which is not there will result in an Index out of bounds exception.
here is a potential solution to your problem -- although this smells of a homework problem.
public class Course {
public string CourseCode { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int NoOfEvaluations { get; set; }
}
List<Course> courses = new List<Course>();
bool CourseAlreadyExists(Course course) {
foreach (Course c in courses) {
if (c.CourseCode == course.CourseCode) {
return true;
}
}
return false;
}
// Define other methods and classes here
public void ImportCourses(string fileName, char Delim) {
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) {
using (var reader = new StreamReader(stream)) {
int index = 0;
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var array = line.Split(Delim);
if (array.Length != 4)
{
throw new ApplicationException(String.Format("Invalid number of fields in record #{0}", index));
}
Course C = new Course();
C.CourseCode = array[0];
C.Name = array[1];
C.Description = array[2];
int evals;
if (!int.TryParse(array[3], out evals))
{
throw new ApplicationException(String.Format("Number of evaluations in record {0} is not in correct format.", index));
}
else
{
C.NoOfEvaluations = evals;
}
if (!CourseAlreadyExists(C))
{
courses[index++] = C;
}
else
{
throw new ApplicationException(String.Format("Course code in record {0} is in use", index));
}
}
}
}
}
}
I am using ExecuteMultipleResponse method to insert 10 account records at a time using SSIS.
List<Entity> _Accounts = new List<Entity>();
// Check the batch size and process
public override void InputAccount_ProcessInput(InputAccountBuffer Buffer)
{
//List<int> personIDs = new List<int>();
int index = 0;
while (Buffer.NextRow())
{
_Accounts.Add(InputAccountFromBuffer(Buffer));
//personIDs.Add(int.Parse(Buffer.sPersonID));
index++;
if (index == 10)
{
ImportBatch();
index = 0;
}
}
ImportBatch();
}
private void ImportBatch()
{
if (_Accounts.Count > 0)
{
var multipleRequest = new ExecuteMultipleRequest()
{
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = true,
ReturnResponses = true
},
Requests = new OrganizationRequestCollection()
};
foreach (var profContact in _Accounts)
{
CreateRequest reqCreate = new CreateRequest();
reqCreate.Target = profContact;
reqCreate.Parameters.Add("SuppressDuplicateDetection", false);
multipleRequest.Requests.Add(reqCreate);
}
ExecuteMultipleResponse multipleResponses = (ExecuteMultipleResponse)organizationservice.Execute(multipleRequest);
var responses = (ExecuteMultipleResponseItemCollection)multipleResponses.Results["Responses"];
foreach (var response in responses)
{
if (response.Fault != null)
{
// A fault has occurred, handle it here
}
else
{
// THIS IS WHERE I KNOW THE GUID VALUE EXIST.
}
}
//IEnumerator f = multipleResponses.Responses.GetEnumerator();
_Accounts.Clear();
}
}
Above code is working fine, however, I now need to read and store Guids from response to a List. This information is essential for the next step in the package. I know, if I am creating single record I can simply say,
Guid newRecord = _service.Create(account);
I even managed to get down to check if the response have 'Fault' or not and if it doesn't have fault then Guid value should exist in the response.
Running response.Response.Results.Values in QuickWatch shows me the guid but I just can't find a way to read it directly and store it as a Guid.
The guid of a created record should be stored in the OrganizationResponse which can be found inside the ExecuteMultipleResponseItem
Try the following to get the guid as a string:
string id = response.Response.Results["id"].ToString()
If it works as expected you should also be able to instantiate a guid, if needed:
Guid guid = new Guid(id);
I am using ExecuteMultipleResponse method to insert 10 account records at a time using SSIS.
List<Entity> _Accounts = new List<Entity>();
// Check the batch size and process
public override void InputAccount_ProcessInput(InputAccountBuffer Buffer)
{
//List<int> personIDs = new List<int>();
int index = 0;
while (Buffer.NextRow())
{
_Accounts.Add(InputAccountFromBuffer(Buffer));
//personIDs.Add(int.Parse(Buffer.sPersonID));
index++;
if (index == 10)
{
ImportBatch();
index = 0;
}
}
ImportBatch();
}
private void ImportBatch()
{
if (_Accounts.Count > 0)
{
var multipleRequest = new ExecuteMultipleRequest()
{
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = true,
ReturnResponses = true
},
Requests = new OrganizationRequestCollection()
};
foreach (var profContact in _Accounts)
{
CreateRequest reqCreate = new CreateRequest();
reqCreate.Target = profContact;
reqCreate.Parameters.Add("SuppressDuplicateDetection", false);
multipleRequest.Requests.Add(reqCreate);
}
ExecuteMultipleResponse multipleResponses = (ExecuteMultipleResponse)organizationservice.Execute(multipleRequest);
var responses = (ExecuteMultipleResponseItemCollection)multipleResponses.Results["Responses"];
foreach (var response in responses)
{
if (response.Fault != null)
{
// A fault has occurred, handle it here
}
else
{
// THIS IS WHERE I KNOW THE GUID VALUE EXIST.
}
}
//IEnumerator f = multipleResponses.Responses.GetEnumerator();
_Accounts.Clear();
}
}
Above code is working fine, however, I now need to read and store Guids from response to a List. This information is essential for the next step in the package. I know, if I am creating single record I can simply say,
Guid newRecord = _service.Create(account);
I even managed to get down to check if the response have 'Fault' or not and if it doesn't have fault then Guid value should exist in the response.
Running response.Response.Results.Values in QuickWatch shows me the guid but I just can't find a way to read it directly and store it as a Guid.
The guid of a created record should be stored in the OrganizationResponse which can be found inside the ExecuteMultipleResponseItem
Try the following to get the guid as a string:
string id = response.Response.Results["id"].ToString()
If it works as expected you should also be able to instantiate a guid, if needed:
Guid guid = new Guid(id);
I am trying to use one attach to the EF to update all the records I need.
public void UpdateSale(Sale s)
{
Context.Sales.Attach(s);
Context.Entry(s).State = System.Data.Entity.EntityState.Modified;
Context.SaveChanges();
}
Lets Say like so. The above code gives me an error because it says the primary keys I am trying to add already exist(They arent automatically generated yet)
Now Sale has a number of different other Entity Models inside it like:
SavedForm, ProductSale
Now the code calling the UpdateSale is here
public JsonResult AddNewForms(string Anamaka, string NispahB, string Hazaot, string ManufactorerID, string ClientStatus, string TypeFile)
{
BL.FormConnectorLogic fcl = new BL.FormConnectorLogic();
DAL.SavedForm AnamakaForm = MakeSavedForm(Boolean.Parse(Anamaka),"מסמך הנמקה",ClientStatus);
DAL.SavedForm NispahBForm = MakeSavedForm(Boolean.Parse(NispahB), "נספח ב", ClientStatus);
DAL.SavedForm HazaotForm = MakeSavedForm(Boolean.Parse(Hazaot), TypeFile, ClientStatus, ManufactorerID);
var results = new { A = AnamakaForm, N = NispahBForm, H = HazaotForm };
return Json(results, JsonRequestBehavior.AllowGet);
}
public DAL.SavedForm MakeSavedForm(bool Authorized, string FormName, string ClientStatus, string ManufactorerID = "")
{
DAL.Sale s = (DAL.Sale)Session["SaleSave"];
DAL.SavedForm sf = new DAL.SavedForm();
if (Authorized)
{
sf = new DAL.SavedForm();
sf.FormName = new BL.FormConnectorLogic().getFormByName(FormName, ClientStatus, ManufactorerID).FormName;
sf.DateFormed = DateTime.Now;
sf.AgentID = s.AgentID;
sf.Status = "פתוח";
sf.SaleID = s.ID;
s.SavedForms.Add(sf);
new BL.SaleLogic().UpdateSale(s);
Session["SaleSave"] = s;
return sf;
}
else return null;
}
Now I've read up on the State and there is a difference between Added and Modified.
While I can't really seem to tell when I am going to add and when I am going to modify.
Is there anyway to disregard everything and to just shove my whole class and all its relationships to the database?