Client-side object model - How same piece of code can load every SP object based on URL? - csom

I need to retrieve some data from SharePoint objects file, folder, list, web, attachment - all possible objects (hope that i didn't miss any).
Since i need to retrieve the data i need only based on URL of the SP object i have a trouble distinguishing between the different object, and that creates a problem with loading the objects correctly.
Meaning the following code:
ctx.Web.GetFolderByServerRelativeUrl(url);
ctx.Load(folder);
try
{
ctx.ExecuteQuery();
}
catch (Exception ex)
{
Console.WriteLine("Not a folder url {0}, the following exception was trown {1}\n", url, ex.Message);
}
Will work for folder relative URL, such as : "/shared%20documents/f1/f2".
But won't work for file relative URL, such as : "/shared%20documents/f1/file.txt".
But i have noticed that the code for List:
Microsoft.SharePoint.Client.List list = ctx.Web.GetList(url);
ctx.Load(list);
try
{
ctx.ExecuteQuery();
}
catch (Exception ex)
{
Console.WriteLine("Not a List url {0}, the following exception was trown {1}\n", url, ex.Message);
}
Works not just for list but also for folders, it returns
/shared%20documents
for /shared%20documents/f1/f2 relative URL !
That brings the following questions:
Do all SP objects can be divided to List and List items (regular folder,file,attachment,list item = list item)?
If yes what about the web object?
How many actors SP online has?
Is it possible to distinguish between the actors types based on their URL?
It it possible to create a peace of code can that would be able to load every SP object based on URL?

There is no way to know the type of the object based only on it URL.
To determine the object type the object can be loaded As File or folder, then in case of failure load as list item, then in case of failure as attachment , then in case of failure as List and in case of failure with some checks on the url determine if it is a site/web url.

Related

How to resolve links to content items inside a rich text ? (Kontent.ai - ASP.NET framework)

So I followed the Kontent doc from the github which allows to retrieve content from a link (https://github.com/Kentico/kontent-delivery-sdk-net/wiki/Resolving-links-to-content-items)
First I implement a resolver to redirect when we click on the link like this :
public class CustomContentLinkUrlResolver : IContentLinkUrlResolver
{
public string ResolveBrokenLinkUrl()
{
return "/404";
}
public string ResolveLinkUrl(ContentLink link)
{
switch(link.ContentTypeCodename)
{
case "author":
return $"/author/{link.UrlSlug}";
default:
return $"/not_found";
}
}
}
Then I register my resolver within a IDeliveryClient
client = DeliveryClientBuilder
.WithProjectId(myid)
.WithContentLinkUrlResolver(new CustomContentLinkUrlResolver())
.Build();
At this moment if i click on the link it will redirect to /author/linkName with an error on the page what I think is normal
I don't get the last part of the doc (how just by doing a getString on the contentItem the link will work ?) so I would like to know how to display the content on the redirect page
I don't know if i was clear enough and sorry for my english
Here is the error thrown on the redirect page
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
The last part of the wiki article refers to something that you already have:
At this moment if i click on the link
If you have a link that you can click on, then you have done what that part of the article describes.
What you need is to resolve the request. If you are getting a 404 that you expect, then you know that you need to add a route to your application to handle the request. In the handler (a controller, a component, etc.) extract the urlSlug from the route and use it with a IDeliveryClient to retrieve the item and then render the content. You will need to filter the GetItems call with something like new EqualsFilter("elements.urlSlug", urlSlug).

Post Data to next Page in Custom Save Action Web Form For Marketer Sitecore 8

After saving data in WFFM Custom save Action,I want to redirect Success Page with some large amount of data
I am trying below line of code .
I Can use Cookies ,session or Query String and Response.Redirect(baseUrl)but i want to Cookies ,session or Query String .
class SaveAction : WffmSaveAction
{
public override void Execute(ID formId, AdaptedResultList adaptedFields, ActionCallContext actionCallContext, params object[] data)
{
//Save Data in Service ,, Redirect to success page with below code with some data like ID
string baseUrl = HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority +
HttpContext.Current.Request.ApplicationPath.TrimEnd('/') + "/success-page";
HttpContext.Current.Response.Clear(); //
StringBuilder sb = new StringBuilder();
sb.Append("<html>");
sb.AppendFormat(#"<body onload='document.forms[""form""].submit()'>");
sb.AppendFormat("<form name='form' action='{0}' method='post'>", baseUrl);
sb.AppendFormat("<input type='hidden' name='id' value='{0}'>", "123456");
// Other params go here
sb.Append("</form>");
sb.Append("</body>");
sb.Append("</html>");
HttpContext.Current.Response.Write(sb.ToString());
HttpContext.Current.Response.End();
// HttpContext.Current.Response.Redirect(baseUrl);
}
}
Above code reload the same page with no body in Html.
Am i missing something in given code ?
The answer might depend on whether you have an mvc form or not.
In case of mvc forms, you might want to read this: http://ggullentops.blogspot.be/2016/07/sitecore-wffm-act-on-success.html. It describes hooking into the success pipeline <wffm.success> and passing data towards the success page (how exactly - querystring, session, .. is up to you(r code)). Fairly easy once you know the correct pipeline.
There is also a great post here describing what you are trying to do - i.e. saving the data for later use in the saveaction. It's too much code to copy here but it comes down to saving the data (in session) during the save action and creating a rendering (to read and handle the data again) that you will place on the success page.
Creating a rendering to place on your success page is something you will have to do anyway.. Don't try to redirect yourself, Sitecore does that for you.

How to show error view after CSV export after directly writing to HttpContext.Current.Response?

In an ASP.NET MVC web application I write directly to HttpContext.Current.Response to export to a CSV file.
This is done in an action in my controller. So I do something like this:
try
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Cookies.Clear();
HttpContext.Current.Response.Charset = System.Text.UTF8Encoding.UTF8.WebName;
HttpContext.Current.Response.ContentEncoding = System.Text.UTF8Encoding.UTF8;
HttpContext.Current.Response.AppendHeader("Pragma", "no-cache");
HttpContext.Current.Response.AppendHeader("Content-Disposition", fileName);
HttpContext.Current.Response.ContentType = "text/csv";
HttpContext.Current.Response.Write("a,b,c\n");
}
catch(Exception)
{
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.SuppressContent = true;
return RedirectToAction("Error");
//return PartialView("ErrorExportingData"); //Prefered!
}
This works without any problem, except that the page is not redirected (or the partial view is not displayed). I guess the problem is that a complete response was already created (and completed).
I flush the response and suppress the content before the redirect, so the exception stack trace does not end up in my CSV file. After this I somehow need to build a new response.
My question is: In this situation, How can I redirect to an error page, after an exception was thrown?
(If somebody wonders why I want to write directly to HttpContext.Current.Response? This is because it is the fastest way to write many records to a CSV file, using a SqlDataReader.)

breeze: querying local cache when using client-side model

Consider the below code. It works fine when getting data from the server. I have a custom data adapter (staffManagemetnService) which creates client-side entities from the json returned by the server.
However, if I make a call to executeQueryLocally, it fails and raises the following exception: Cannot find an entityType for resourceName: 'GetInternalResourcesByCompetence'. Consider adding an 'EntityQuery.toType' call to your query or calling the MetadataStore.setEntityTypeForResourceName method to register an entityType for this resourceName
var query = breeze.EntityQuery.from('GetInternalResourcesByCompetence').withParameters(parameters);
var result = self.manager.executeQueryLocally(query.using(dataService.staffManagementService));
if (result) {
return $q.resolve(result);
} else {
return this.manager.executeQuery(query.using(dataService.staffManagementService))
.then(function (data) {
return data.results;
})
.catch(function (err) {
logError('Restrieving resources days off failed', err, true);
});
}
I'm not sure what this means. Should it not work out-of-the-box since I've specifically asked breeze to use the custom dataAdapter ?
It's important to different between resource names and entity type names. Resource names are usually part of an endpoint and in plural (eg orders). Type names are typically singular (eg order).
Locally breeze cannot do much with the resource name, since it won't call the endpoint. Instead you ask for a certain entity type name.
You can map an entityType to a resourcename using the setEntityTypeForResourceName function:
metadataStore.setEntityTypeForResourceName('Speakers', 'Person');
See chapter "Resources names are not EntityType names" and the following chapters here: http://www.getbreezenow.com/documentation/querying-locally

Multi Post for Action with return File in ASP.NET MVC

Assume this code in One of my Actions
[HttpPost]
public ActionResult Generate (Params){
....
InsertOneRawToDB();
return RedirectToAction("Index", new { info = info });
}
So every thing is OK yet but when I change return to:
InsertOneRawToDB();
byte[] myfile = GenerateAZipFile();
return File( myfile , "application/zip" , "MyFileName");
In this case I see a weird behavior: before return, One raw inserted to DB, and after return another raw inserted, it seems the InsertOneRawToDB called again.
Does any one know about this? what happening here?
PS: I use Visual Studio 2012 RTM + ASP.NET MVC4
PS: OK I Use IDM (Internet Download Manager) to download zip file and that cause MultiPost on this Action So How can I handle this?
Based on your conclusion that the problem is related to using a download manager... That's what download mangers do. They create multiple connections to the file.
One thing you could do is store a session variable that says "Already started downloading", and then only insert the record the first time.
however if the user legitimately downloaded the file multiple times then you would only get one record.
Another option would be to examine the Http headers and look for the "Range" header, which is what is used to download a file in multiple pieces (or resume a file). You would then have to take the Range parameters and only return the portion of the file requested.
Here's an example of how to do a Ranged download: http://tpeczek.com/2011/10/range-requests-in-aspnet-mvc.html
I'm actually quite surprised that this hasn't come up before... I guess most people don't do database actions in a download action or notice it.
You can redirect to new action and in this new action return file.
[HttpPost]
public ActionResult Generate (Params){
....
InsertOneRawToDB();
return RedirectToAction("GetFile"};
}
[HttpGet]
public ActionResult GetFile
{
byte[] myfile = GenerateAZipFile();
return File(myfile, "application/zip", "filename.ext");
}

Resources