So...i created a Sharepoint Add-in (C# MVC) to get list information and create/update items. I've done the creating/updating in the past, not gonna tackle that now.
My problem here is displaying the list items into the MVC View. What i've done so far ->
I created a model (class) with the information that i'll show in the table:
public class IRFItem
{
public string Title { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
//public string CreatedBy { get; set; }
}
In the same file (for the sake of keeping my tests compact) i also added a way to get the items i need:
public static List<IRFItem> GetItems(SharePointContext spContext, CamlQuery camlQuery)
{
List<IRFItem> items = new List<IRFItem>();
//var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
using (var clientContext = spContext.CreateUserClientContextForSPAppWeb())
{
if (clientContext != null)
{
List irfList = clientContext.Web.Lists.GetByTitle("IRF");
ListItemCollection irfListItems = irfList.GetItems(camlQuery);
clientContext.Load(irfListItems);
clientContext.ExecuteQuery();
if (irfListItems != null)
{
foreach (var irfListItem in irfListItems)
{
items.Add(
new IRFItem
{
Title = irfListItem["Title"].ToString(),
StartDate = irfListItem["StartDate"].ToString(),
EndDate = irfListItem["EndDate"].ToString(),
});
}
}
else
{
items.Add(
new IRFItem
{
Title = "Empty",
StartDate = "Empty",
EndDate = "Empty"
});
}
}
}
return items;
}
In my custom controller (called SharepointController so i dont mess up with the default ones) i added this ->
// GET: Sharepoint
[SharePointContextFilter]
public ActionResult Index()
{
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
ViewBag.Username = SharePointService.GetUserName(spContext);
CamlQuery queryProducts = new CamlQuery();
queryProducts.ViewXml =
#"<View>
<ViewFields><FieldRef Name='StartDate' /><FieldRef Name='LinkTitle' /><FieldRef Name='Title' /><FieldRef Name='Author' /><FieldRef Name='EndDate' /><FieldRef Name='ID' /></ViewFields>
</View>";
List<IRFItem> items = SharePointService.GetItems(spContext, queryProducts);
//SharePointService.GetItems(spContext, queryProducts);
return View(items);
}
And finally my desired view contains->
#foreach (AddinTest1Web.Models.IRFItem irfItem in Model)
{
<tr>
<td>#irfItem.Title</td>
<td>#irfItem.StartDate</td>
<td>#irfItem.EndDate</td>
</tr>
}
I get no errors, but my table is always empty...I even added that else part in GetItems to create an item that shows empty just so i know if its a sharepoint related problem or something else. My MVC experience isn't much to be honest (just started learning it a week ago, but im the kind of guy that learns by doing).
Does anyone see any problems here? I've followed a tutorial for this and made my own little changes.
Ref: https://www.chakkaradeep.com/2013/10/18/building-apps-for-sharepoint-with-mvc/
Any kind of tip will be highly appreciated, thx.
EDIT: I jumped over the error by giving the application more permissions (to list & web just to be safe) and i am getting back results, however i am unable to create the items because executeQuery does not finish on time. Any idea how to delay that? I remember i had a bigggg problem with tasks in the past so i have no idea where to start here.
Couple of things I see from debugging.
I would move the code GetItems() to separate Helper class and then put a breakpoint in it to see if it is firing.
If you are not getting any error and return data is always empty, then that means that some part of the code is not getting executed (Sync or async issue?)
Ok so i fixed the problem (been fighting with this for hours and it was so damn simple i wanna punch myself right now).
In case anyone encounters this ->
Why my list didnt get any items (even tho no erorrs) -> Not enough permissions given to the app. Fixed by giving full list permissions and full web permissions.
Why my foreach was giving an error -> Apparently one column had a different name. I figured that out by trying this code (which apparently is better cause it throws an error, unlike getting everything from the list) ->
clientContext.Load(irfListitems,
itemss => itemss.Include(
item => item["Title"],
item => item["StartDate"],
item => item["EndDate"]
));
Related
I'm working on an ASP.Net MVC project, and I've hit a (seemingly) very strange error. I have a model named Lens, here is the class structure for it
public class Lens
{
public int LensID { get; set; }
public string LensName { get; set; }
}
In one of my views, I have a list of lenses (acquired in controller). I'm getting an ArgumentOutOfRangeException in the following code snippet
#for (int i = 0; i < Lenses.Count; i++)
{
<input type="text" data-LID="#Lenses[i].LensID" value="#Lenses[0].LensName" readonly id="lens #i" />
}
Lenses is the list I get from the controller. I really can't understand why this code is throwing an exception. I looked at the Locals view in my debugger and found that, at the time that the exception is thrown, the value of the argument i is 0, and there is a Lens object at index 0 of Lenses. Even stranger, when I use a foreach loop to pull from the exact same list, it has no issue retrieving the object. I've also tried
#Lenses[0].LensID
Instead, and I got the same error. Also, in case it's relevant. According to the Locals view, the Lenses list has a Count of 1. Here's the creation of Lenses
List<Lens> Lenses = (List<Lens>)ViewBag.Lenses;
And here's how it's being sent to the View from Controller
LensQueries lQuery = new LensQueries();
ViewBag.Lenses = lQuery.GetAll();
And here's the reference for LensQueries.GetAll()
public List<Lens> GetAll()
{
List<Lens> retList;
using (var context = new SqlDbContext())
{
retList = context.Lenses.SqlQuery("select *from dbo.Lens").ToList<Lens>();
}
return retList;
}
Found the solution (kinda?). Still have no idea why it was breaking but when I went into my references and deleted certain assemblies, the issue went away.
For anyone curious, the assemblies I removed were the Owin.Security.Providers assembly, as well as all of it's sub-assemblies.
So my goal is to use ElasticSearch, ES, as a log. To be more specific, i want to upload basically just a timestamp from when my application last ran. The uploading works fine but i cannot figure out how to fetch the data from the index. I've tried both using the Query and Aggregetion but in neither of cases have I managed to get some data. I get a response that says :
Valid NEST response built from a low level call on POST: /lastrun/lastrun/_search.
I have also tried searching for solutions but cannot manage to find anything that works for me. Can anyone help me fetch the data?
The index name is 'lastrun' and the class I upload to the index is called LastRun.
The Logger class
public static Boolean WriteLastRun()
{
var response = Elastic.Index(new LastRun { Date = DateTime.Now });
return response.IsValid ? true : false;
}
public static DateTime ReadLastRun()
{
var SearchResponse = Elastic.Search<LastRun>(s => s
.Query(q => q.MatchAll())
.Index("lastrun"));
Console.WriteLine(SearchResponse.Documents);
return new DateTime();
}
The LastRun class I upload to ES.
public class LastRun
{
public DateTime Date { get; set; }
}
Thanks!
EDIT
Settings for the Elastic:
var settings = new ConnectionSettings(new Uri("http://localhost:9200/")).DefaultIndex('lastrun');
ElasticClient Elastic = new ElasticClient(settings);
EDIT 2
I can verify that the same index is being uploaded to and searched by this code and by checking the same index in kibana.
var resolver = new IndexNameResolver(settings);
var index = resolver.Resolve<LastRun>();
Console.WriteLine(index); //prints 'lastrun'
Turns out that there wasn't a problem from the beginning. The Search method worked fine and I had the wrong ideá of accessing the doc in the respons.
This is what is did, which was wrong:
Console.WriteLine(SearchResponse.Documents);
And here the right way to do it:
foreach (var item in SearchResponse.Documents)
{
Console.WriteLine(item.Date)
}
Following some major refactoring (moving to a PCL) I have some code (which was not part of the refactor) that was running fine but is now throwing exceptions.
The code is part of a Xamarin Android project which was using File Linking before the move to a Portable Class Library.
It's a simple thing but I can't see why this would happen
foreach(var station in stationList)
{
// Breakpoint on next line shows station to be null..!
if(station.ClusterId != Guid.Empty)
{
// Code in here
}
}
The problem is that although the stationList contains a number of StationViewModel objects the station instance is always null - how can that be?
I have tried replacing the foreach with a for loop but the result was the same - station was null.
I've also restarted Visual Studio and rebooted.
No Xamarin updates appear to be outstanding.
The code was running fine and the generation of the stationList has not changed nor has the implementation of this class.
EDIT:
The stationList creation process is:
Call made to SQLite 'repo' in PCL which returns IList<station> (which is populated)
_loadedStations = await _stationManager.GetStationsAsync();
Using AutoMapper a new List<StationViewModel> is generated from the above list (which is populated correctly)
fullStationList = AutoMapper.Mapper.Map<IList<Station>, IList<StationViewModel>>(_loadedStations);
In a separate method the view model list above is filtered based on the LatLng coordinates.
var stationList = fullStationList.Where(x => mapBounds.Contains(new LatLng(x.Latitude, x.Longitude))).ToList();
The foreach follows the above line of code..
SOLUTION:
Well I've 'solved' the problem but still don't know what caused it.
In the same method as the foreach there is another, contained within an if. It too has the station identifier;
if (zoomChanged)
{
foreach (var station in fullStationList)
{
station.ClusterId = Guid.Empty;
}
RunOnUiThread(() => _stationMap.Clear());
_clusters.Clear();
}
By changing either of the variable names the code will run fine and the previously erroring loop will run without any problem.
Note that this 2nd loop was not within the 1st one - that's obviously
not going to work, but I can't see why this was causing a problem.
It seems like this has something to do with the way Xamarin works , changing var name solves the issue
foreach(var stationItem in stationList)
{
// Breakpoint on next line shows station to be null..!
if(stationItem.ClusterId != Guid.Empty)
{
// Code in here
}
}
I tried it in this way and it works:
internal class CStation
{
private Guid _clusterId;
public CStation()
{
_clusterId = Guid.NewGuid();
}
public Guid StationName
{
get { return _clusterId; }
}
}
private voit TestList()
{
List<CStation> stationList = new List<CStation>();
CStation test1 = new CStation();
CStation test2 = new CStation();
CStation test3 = new CStation();
stationList.Add(test1);
stationList.Add(test2);
stationList.Add(test3);
foreach (var station in stationList)
{
// Breakpoint on next line shows station to be null..!
if (station == null )
{
throw new ArgumentNullException();
}
}
}
I think you didnt instantiate the Guid.
I did it in the constructor of Station -> _clusterId = Guid.NewGuid();
We are having an issue with searching a custom record through SuiteTalk. Below is a sample of what we are calling. The issue we are having is in trying to set up the search using the internalId of the record. The issue here lies in in our initial development account the internal id of this custom record is 482 but when we deployed it through the our bundle the record was assigned with the internal Id of 314. It would stand to reason that this internal id is not static in a site per site install so we wondered what property to set up to reference the custom record. When we made the record we assigned its “scriptId’ to be 'customrecord_myCustomRecord' but through suitetalk we do not have a “scriptId”. What is the best way for us to allow for this code to work in all environments and not a specific one? And if so, could you give an example of how it might be used.
Code (C#) that we are attempting to make the call from. We are using the 2013.2 endpoints at this time.
private SearchResult NetSuite_getPackageContentsCustomRecord(string sParentRef)
{
List<object> PackageSearchResults = new List<object>();
CustomRecord custRec = new CustomRecord();
CustomRecordSearch customRecordSearch = new CustomRecordSearch();
SearchMultiSelectCustomField searchFilter1 = new SearchMultiSelectCustomField();
searchFilter1.internalId = "customrecord_myCustomRecord_sublist";
searchFilter1.#operator = SearchMultiSelectFieldOperator.anyOf;
searchFilter1.operatorSpecified = true;
ListOrRecordRef lRecordRef = new ListOrRecordRef();
lRecordRef.internalId = sParentRef;
searchFilter1.searchValue = new ListOrRecordRef[] { lRecordRef };
CustomRecordSearchBasic customRecordBasic = new CustomRecordSearchBasic();
customRecordBasic.recType = new RecordRef();
customRecordBasic.recType.internalId = "314"; // "482"; //THIS LINE IS GIVING US THE TROUBLE
//customRecordBasic.recType.name = "customrecord_myCustomRecord";
customRecordBasic.customFieldList = new SearchCustomField[] { searchFilter1 };
customRecordSearch.basic = customRecordBasic;
// Search for the customer entity
SearchResult results = _service.search(customRecordSearch);
return results;
}
I searched all over for a solution to avoid hardcoding internalId's. Even NetSuite support failed to give me a solution. Finally I stumbled upon a solution in NetSuite's knowledgebase, getCustomizationId.
This returns the internalId, scriptId and name for all customRecord's (or customRecordType's in NetSuite terms! Which is what made it hard to find.)
public string GetCustomizationId(string scriptId)
{
// Perform getCustomizationId on custom record type
CustomizationType ct = new CustomizationType();
ct.getCustomizationTypeSpecified = true;
ct.getCustomizationType = GetCustomizationType.customRecordType;
// Retrieve active custom record type IDs. The includeInactives param is set to false.
GetCustomizationIdResult getCustIdResult = _service.getCustomizationId(ct, false);
foreach (var customizationRef in getCustIdResult.customizationRefList)
{
if (customizationRef.scriptId == scriptId) return customizationRef.internalId;
}
return null;
}
you can make the internalid as an external property so that you can change it according to environment.
The internalId will be changed only when you install first time into an environment. when you deploy it into that environment, the internalid will not change with the future deployments unless you choose Add/Rename option during deployment.
I'm hoping that I'm just using the API incorrectly, but for some reason, when I query my oData service from wp7, I am only receiving the last entry in the sequence. I'm pretty sure the service is working just fine as I'm able to just visit the oData query URL in the browser and get the correct results. However, the following method only ends up displaying one item on the list.
I based the following code from the sample at this blog post: http://chriskoenig.net/2010/10/30/odata-v2-and-windows-phone-7/
The observable collection which is passed in is the one which is bound to the wpf listbox.
private static void LoadRuntimeData(ObservableCollection<CategoryItem> items)
{
var catalog = GetCatalog();
var queryUri = new Uri("/Categories?&$orderby=Name", UriKind.Relative);
var categories = new DataServiceCollection<Category>(catalog);
var queryHandle = App.ViewModel.StartQuerying();
categories.LoadAsync(queryUri);
categories.LoadCompleted += (e, c) =>
{
using (queryHandle)
{
var serverItems = categories.Select(k => new CategoryItem
{
Name = k.Name,
Description = k.Description
});
items.Clear();
foreach (var item in serverItems)
{
items.Add(item);
}
}
};
}
Any tips would be greatly appreciated.
Edit: per a comment below, I've uploaded the source code in which this issue is reproducible: http://khanviewer.codeplex.com/
Taking a quick stab at this (and I suspect that Chris would know better).
But don't you need to somehow identify/tag with an attribute a primary key column (the property or properties that define uniqueness).
I know I have run into something similar to this with RIA Services, and the issue there was that I wasn't setting a value for the unique identifier column. As a result I saw all my data come down, but the when the client got the data it saw all the data as a single record.
Jay