Recursive search for sites using Client Object Model using Site Id (GUID) - caml

Using the Client Object Model I am looking for the most efficient way to search a SharePoint server and determine if a specific subsite exists given its unique ID (GUID). We are storing the GUID in our external system because we need to get back to the site and the GUID is the only property that can not change. I know that CAML can be used to search for data within a specific site. However, I haven't been able to find an API that will do this for subsites. I am forced to do a recursive search and use a for loop. In my case, we could have thousands of sites nested on our server.
This logic does one level -- but is not efficient when thousands of subsites exists.
public bool SiteExists(ClientContext context, string myGuid)
{
Web oWebsite = context.Web;
context.Load(oWebsite, website => website.Webs, website => website.Title, website => website.Description, website => website.Id);
context.ExecuteQuery();
for (int i = 0; i != oWebsite.Webs.Count; i++)
{
if (String.Compare(oWebsite.Webs[i].Id.ToString(), myGuid, true) == 0)
{
return true;
}
}
return false;
}

public bool SiteExists(ClientContext context, string myGuid) {
Guid id = new Guid(myGuid);
Site site = context.Site;
Web foundWeb = site.OpenWebById(id);
context.Load(foundWeb);
context.ExecuteQuery();
if(foundWeb != null) {
return true;
}
return false;
}

Related

How to pass variable(&id) from one api to another to fetch corresponding data?

I want to display players stats in listview for which I am consuming this api: https://cricapi.com/api/playerStats?apikey=apikey&pid=pid
Output of above api is:
{
"pid": xxxx,
"profile": "profile description",
"imageURL": "https://www.cricapi.com/playerpic/xxxx.jpg",
pid for each player is retrieved from another api:
https://cricapi.com/api/playerFinder?apikey=apikey&name=playerName
Output of above api is:
{
"data": [
{
"pid": xxxx,
"fullName": "Firstname Lastname",
Currently, I am passing hardcoded pid in first api to display player's stats and code for it is:
FetchJson() async {
var response = await http.get(
'https://cricapi.com/api/playerStats?apikey=apikey&pid=1111');
if (response.statusCode == 200) {
String responseBody = response.body;
var responseJson = jsonDecode(responseBody);
pid = responseJson['pid'];
name = responseJson['name'];
playingRole = responseJson['playingRole'];
battingStyle = responseJson['battingStyle'];
country = responseJson['country'];
imageURL = responseJson['imageURL'];
data = responseJson;
var stats = data['data']['batting'];
var testStats = stats['tests'];
var odiStats = stats['ODIs'];
var tStats = stats['T20Is'];
// T20 Stats
matches_t = tStats['Mat'];
runs_t = tStats['Runs'];
half_t = tStats['50'];
century_t = tStats['100'];
highest_t = tStats['HS'];
avg_t = tStats['Ave'];
And I am calling FetchJson() inside initState().
I tried solution given on my similar / earlier question How to fetch api data by passing variables (parameters)?, but that led me to a different path. I cannot implement that solution, since there's no way for me to return pid through first api that will be received by FetchJson().
My question is:
How to retrieve pid from second api (playerFinder) and feed it to first api (playerStats) and how to make use of that pid so that instead of passing hardcoded pid, I can pass pid as variable and can display multiple players stats in UI?
Required code is here : https://pastebin.com/iU8x9U8z
I want to show players stats in UI but currently I am passing hardcoded playerid which is showing me only one player's stats, but I would like to show different players stats.
**********UPDATE *************
As an alternate solution, I am now using list of pids and parsed those using map and passing them to FetchJson() inside for loop, as below:
var playerIds = [{"pid":35320},{"pid":28114},{"pid":28779},{"pid":28763},{"pid":30176},{"pid":7133},{"pid":5390}]
#override
void initState() {
var intIds = playerIds.map<int>((m) => m['pid'] as int).toList();
for (int i = 0; i < intIds.length; i++) {
FetchJson(intIds[i]);
}
}
FetchJson(int ids) async {
print(ids);
var response = await http.get(
'https://cricapi.com/api/playerStats?apikey=apikey&pid=$ids');
....
}
The issue I am now facing with this approach is, its taking last pid from the list and displaying its data in UI repeatedly. The expected output I want to see is: players data for all pids in UI and I am not sure how to achieve this.
Complete referenced code here: https://pastebin.com/kFYBfHuf
One answer is to create Maps from both sets of api's down to desirable player data then use a switch statement as written below similar to a where clause in order to identify matching data.
The big problem is that you need to identify matching data items in both api's. In my example I've assumed it may be a players name or it could be their team and team number, but there has to be something that validates you are looking at differing data points for the same player.
switch(variable_expression) {
case name = full_name: {
// statements;
}
break;
case constant_expr2: {
//statements;
}
break;
default: {
//statements;
}
break;
}

Using an HTML actionlink to sort a list

I have a list of possible entries stored in a database. I sort and display these entries into a new view depending on an entry put into a textbox, or from clicking on an html actionlink. The main idea of this can be seen below.
public ActionResult Index(string sortOrder, string searchString, int? sortType)
{
if (!String.IsNullOrEmpty(searchString))
{
if (sortType == 1)
{
//Sort the results strictly based on the HTML header options
applications = applications.Where(s => s.Business.Equals(searchString));
}
else
{
//sort based on the input of the form
applications = applications.Where(s => s.Business.Contains(searchString)
|| s.ApName.Contains(searchString));
}
}
return View(applications.ToList());
}
The first part of this if statement is activated by clicking a link like so,
<li>#Html.ActionLink("CITY", "index", "app", new {SearchString = "city", sortType=1}, null)</li>
Although my code is working, I'm just wondering if there is a more "proper" way of doing what I coded, without having to pass a sortType variable to determine whether to sort based on the form or the actionlink. I'm sure what I have done is quite a bad way of doing it, but I'm very new to this.
I'm not sure if this is what you are after because your question keeps talking about sorting but your code is talking about filtering. You could try to specify default values so the Where statements short-circuit when those criteria are not populated. Ex:
public ActionResult Index(string city = null, string business = null){
var model = applications
.Where(x => city == null || x.City.Contains(city))
.Where(x => business == null || x.Business == business);
return View(model);
}

Selenium and html agility pack drops html

I'm using the HTML Agility Pack and Selenium to crawl a site, find particular tables, and then parse those tables. Everything works fine individually, but when I run the app, it sometimes drops huge chunks of HTML from within the table. When I track down the page on the site with the data, the HTML is there. For whatever reason, it isn't there when the crawler is running.
Here's the code. The rows[r].InnerHtml is NOT the HTML from page. Anyone have any thoughts on what might be happening here?
public IMyInterface CreateObjectFromHtmlRow(HtmlNode rowNode)
{
try
{
var columns = rowNode.SelectNodes("td");
MyClass obj = new MyClass()
{
OnlineId = columns[0].InnerText.Trim(),
FirstName = columns[1].InnerText.Trim(),
MiddleInitial = columns[2].InnerText.Trim(),
LastName = columns[3].InnerText.Trim(),
Residence = columns[4].InnerText.Trim(),
};
return obj;
}
catch (Exception exc)
{
_logger.LogFormat("Error trying to parse row: {0}", exc.Message);
return null;
}
}
IMyInterface obj = null;
obj = _repository.CreateObjectFromHtmlRow(rows[r]);
if (obj == null)
{
_logger.LogFormat("Unable to create object from this data: {0}", rows[r].InnerHtml);
}
else
{
// Do something useful
}
Thanks for your help.
WW

How to get the document using view in couchbase

I have a requirement wherein I have get the document from couchbase.
Following in the Map function that I am using for the same -
function (doc, meta) {
if (meta.type == "json" && doc!=null) {
emit(doc);
}
}
There is no reduce function. Also following is my java code to get the document -
List<URI> hosts = Arrays.asList(
new URI("http://<some DNS with port>/pools")
);
// Name of the Bucket to connect to
String bucket = "Test-Sessions";
// Password of the bucket (empty) string if none
String password = "";
//System.setProperty("viewmode", "development");
// Connect to the Cluster
CouchbaseClient client = new CouchbaseClient(hosts, bucket, password);
String designDoc = "sessions";
String viewName = "by_test";
View view = client.getView(designDoc, viewName);
Query query = new Query();
query.setIncludeDocs(true);
query.setKey(String.valueOf(122));
ViewResponse result = client.query(view, query);
Object object = null;
for(ViewRow row : result) {
if(null != row) {
object = row.getDocument();
}// deal with the document/data
}
System.out.println("Object" + object);
And the data that I have in couchbase is key - "122" and value - "true". But for some reason , I do not get any rows in the ViewResponse. What is going wrong can anyone help?
I don't understand what you are trying to achieve here, you are using a view to get a document by it's key? Key == 122? Why can't you just do client.get(122) ?
If you just need a list of all the keys in your bucket (of which you can use to pull back all documents via include docs) then make your function like so:
function (doc, meta) {
if (meta.type == "json") {
emit();
}
}
The key of the document is always emitted as an ID (viewRow.getId()). You don't need to emit the document, try to emit as little data as possible to keep view sizes small.
If you are needing to manipulate all the documents in your bucket be careful as the size grows, perhaps you'd need to look at pagination to cycle through the results. http://tugdualgrall.blogspot.com.es/
Also once you have the ViewResponse loop over it like so:
for(ViewRow row : result) {
row.getDocument(); // deal with the document/data
}
You don't need to be doing checks for null on the rows.

Entity Framework Code First - Orphaning solutions?

I have searched around for a good amount of time trying to find a satisfactory solution to the orphan issue common in EF.
One of the simplest forms of orphaning is the clearing of a collection of entities. The relationship between the entities is removed but the child entities still remain in the database.
My requirements: -
The clearing of the collection occurs in the domain and I want to simply be able to call clear and no more.
Any logic to figure out whether the relationship between the parent and child has been broken resulting in the delete needs to be encapsulated within the repository / DbContext.
I don't want to have to 'dirty' the domain with anything additional in order to solve this problem. This includes back references.
I suspect that this can't be solved as I have have spent considerable time looking for solutions but I ask out of hope!
Areas I have looked at are the ChangeTracker and any possible events which I can hook into, similar to AssociationChanged event which has popped up in various places. Something, somewhere in the DbContext must know that this relationship has been broken. How to access it, that is the question?
Thanks.
Can you try the following solution? Mb it fits your needs. The DeleteOrphans extension method must be called between DetectChanges and SaveChanges methods.
public static class DbContextExtensions
{
private static readonly ConcurrentDictionary< EntityType, ReadOnlyDictionary< string, NavigationProperty>> s_navPropMappings = new ConcurrentDictionary< EntityType, ReadOnlyDictionary< string, NavigationProperty>>();
public static void DeleteOrphans( this DbContext source )
{
var context = ((IObjectContextAdapter)source).ObjectContext;
foreach (var entry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
{
var entityType = entry.EntitySet.ElementType as EntityType;
if (entityType == null)
continue;
var navPropMap = s_navPropMappings.GetOrAdd(entityType, CreateNavigationPropertyMap);
var props = entry.GetModifiedProperties().ToArray();
foreach (var prop in props)
{
NavigationProperty navProp;
if (!navPropMap.TryGetValue(prop, out navProp))
continue;
var related = entry.RelationshipManager.GetRelatedEnd(navProp.RelationshipType.FullName, navProp.ToEndMember.Name);
var enumerator = related.GetEnumerator();
if (enumerator.MoveNext() && enumerator.Current != null)
continue;
entry.Delete();
break;
}
}
}
private static ReadOnlyDictionary<string, NavigationProperty> CreateNavigationPropertyMap( EntityType type )
{
var result = type.NavigationProperties
.Where(v => v.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
.Where(v => v.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One || (v.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne && v.FromEndMember.GetEntityType() == v.ToEndMember.GetEntityType()))
.Select(v => new { NavigationProperty = v, DependentProperties = v.GetDependentProperties().Take(2).ToArray() })
.Where(v => v.DependentProperties.Length == 1)
.ToDictionary(v => v.DependentProperties[0].Name, v => v.NavigationProperty);
return new ReadOnlyDictionary<string, NavigationProperty>(result);
}
}