I'm trying to consume twitter's REST api mentioned at this link using WCF REST starter kit mentioned at this link.
I'm using the same objects in DataContract as mentioned in the article - statusList and status.
[assembly: ContractNamespace("", ClrNamespace = "TwitterShell")]
[CollectionDataContract(Name = "statuses", ItemName = "status")]
public class statusList : List<status> { }
public class user
{
public string id;
public string name;
public string screen_name;
}
public class status
{
public string id;
public string text;
public user user;
}
I'm reading the XML contents using ReadAsDataContract() method.
HttpClient http = new HttpClient("http://twitter.com/statuses/");
http.TransportSettings.Credentials =
new NetworkCredential("{username}", "{password}");
HttpResponseMessage resp = http.Get("friends_timeline.xml");
resp.EnsureStatusIsSuccessful();
statusList sList = resp.Content.ReadAsDataContract<statusList>();
And I get the following exception. I have not defined the following namespace at all.
Error in line 1 position 24. Expecting element 'statuses' from namespace 'http://schemas.datacontract.org/2004/07/sitename'.. Encountered 'Element' with name 'statuses', namespace ''.
Please help. Thanks.
Just don't do it. You are in for a world of pain if you try using Datacontracts and operation contracts to access non-wcf services.
Ok, so I guess that was a bit unfair leaving you high and dry without an alternative, so try this:
var response = client.Get("http://twitter.com/statuses/friends_timeline.xml");
var statuses = response.Content.ReadAsXElement();
var statusQuery = from st in statuses.Elements("status")
select new status {
id = st.Element("id").Value,
text = st.Element("text").Value,
user = (from us in st.Elements("user")
select new user {
id = us.Element("id").Value,
name = us.Element("name").Value,
screen_name = us.Element("screen_name").Value
}).FirstOrDefault()
};
var statuses = statusQuery.ToList();
Using Linq to XML to create objects from the XML document allows you to avoid the magic of serializers and completely control the names and datatypes of your client side objects. It would be really easy to wrap this as a new HttpContent extension method so that you could simply do:
var statuses = response.Content.ReadAsTwitterStatuses();
I came across your post searching for answers to the same problem and I was able to find a solution for what you are looking for if you want to forgo the LINQ to XML approach.
1) Make sure you annotate your Status class with the following decoration
[DataContract (Namespace = "")]
By specifying the above annotation, you are overriding the namespace from the default namespace of your class. This should fix your namespace problem.
2) To address the issues of nulls (which I also experienced), order of your fields are very important. When your objects are deserialized, it is done in alphabetically order. You can order your fields to match the order of the incoming XML using the Order property on the DataMember annotation.
e.g.
[DataMember (Order = 1)]
public string text
etc ...
Related
I am consuming an API mehod and it returns response as of type Product and below is the response class structure.
Public class Product
{
public int Id;
public string Name;
public IList<Product> MasterProduct { get; set; }
}
The API result include the product attributes along with IList. Since this API cannot be consumed directly though our windows client we have a wrapper web API which consume this API, for this in the local API we have defined similar Product class. The issue I am facing is when trying to map the attibues of external API with local. Below is what I am trying to do.
response = Response.Result.Select(x => new Product
{
Id=x.Id,
Name=x.Name
MasterProduct = x.MasterProduct.Cast<MasterProduct>().ToList()//tried below
}).ToList();
but it fails with error as - Unable to cast object of type 'Api.Models.Product' to type 'App.DataContracts.Product'
The Masterproduct consist of hierarchal data .I am wondering if the approach I am taking is right or it has to be done through some method. Any suggestion or help would be appreciated.
Upon searching the web I came across some code where serpare method is being called to parse using Microsoft.Its.Data, but this was for single object where as in my case I have a List(Hierarchical).
Appreciate if someone can point to some linke/sampel to achive the same.
Trying serialization/deserialization would do. Below is the code
Perhaps trying serialization/deserialization would do.
if (response.Result != null)
{
var serializedResponse = JsonConvert.SerializeObject(Response.Result, Formatting.Indented);
response = JsonConvert.DeserializeObject<List<Product>>(serializedResponse);
}).ToList();
return response;
I saw a related question:
Sitecore Glass Mapper always null
But unfortunately it does not give a solution for my case.
Here goes a code snippet:
var db = Factory.GetDatabase("master");
var context = new SitecoreContext();
// the ID of Needed item
var g = new Guid("{F21C04FE-8826-41AB-9F3C-F7BDF5B35C76}");
// just to test if it's possible to fetch item using db.GetItem
var i = db.GetItem(new ID(g), Language.Current, Sitecore.Data.Version.Latest);
// Grab item
var t = context.GetItem<Article>(g);
In the code above:
i is not null
t is null
Article is the simple class like:
[SitecoreType(TemplateId = "{4C4EC1DA-EB77-4001-A7F9-E4C2F61A9BE9}")]
public class Article
{
[SitecoreField(FieldName = "Title")]
public string Title { get; set; }
}
There are only one language installed in Sitecore - en, it has been specified in the web.config in the items as well.
Also I have added GlassMapperSc.Start(); to Application_Start in the Global.asax.cs and added my assembly to the list of included assemblies via var attributes = new AttributeConfigurationLoader(new[] { "Assembly.Name" }); and I succeeded to find my class in the SitecoreContext mappings.
It does not looks like a language issue, as stated in the link provided in the very beginning. And I'm struggling with it already for a pretty long time, but no luck...
Thank You!
I just noticed that you are using master db for the Sitecore DB and SitecoreContext for Glass.
The SitecoreContext class will use the database that is defined by the Sitecore.Context.Database property at runtime. This probably means that it is using the web database.
Can you check that you have published the item to the web database or instead using:
var context = new SitecoreService("master");
I think I could be using this wrong, there wasn't much on the Ninject variant of multiple cores, but I'm trying to use Ninject and SolrNet. While taking advantage of fully loose mapping. So I know I need to use Ninject named bindings. Can't use Windsor, it's dll's don't seem to play well with our current stuff.
Suspect code:
SolrServers cores = new SolrServers();
cores.Add(new SolrServerElement
{
Id = "index1",
DocumentType = typeof(ISolrOperations<Dictionary<string, object>>).AssemblyQualifiedName,
Url = "http://localhost:8080/solr/index1",
});
cores.Add(new SolrServerElement
{
Id = "index2",
DocumentType = typeof(ISolrOperations<Dictionary<string, object>>).AssemblyQualifiedName,
Url = "http://localhost:8080/solr/index2",
});
var kernal = new StandardKernel(new SolrNetModule(cores));
var operations = kernal.Get<ISolrOperations<Dictionary<string, object>>>("index1");
Error Produced:
Test 'Test.DifferentTest' failed:
Ninject.ActivationException : Error activating ISolrOperations{Dictionary{string, Object}}
No matching bindings are available, and the type is not self-bindable.
Activation path:
1) Request for ISolrOperations{Dictionary{string, Object}}
I understand the concept of DI, however I don't know much more than that because in MVC everything seemed hidden from me. So any additional explanation, on why this is dumb/how SolrNet interacts with it, would be appreciated.
Link to SolrNet Module https://github.com/mausch/SolrNet/blob/master/Ninject.Integration.SolrNet/SolrNetModule.cs
Since I see that you are using the fully loose mapping capabilities of SolrNet, you could implement the following dynamic mappings as a workaround until support for the same type/class is added to SolrNet for Ninject.
public class Index1Item
{
SolrField["*"]
public IDictionary<string, object> Fields { get; set; }
}
public class Index2Item
{
SolrField["*"]
public IDictionary<string, object> Fields { get; set; }
}
Please see Mappings on SolrNet project page for more details on this dynamic mapping.
Then your SolrNet setup would change to the following:
SolrServers cores = new SolrServers();
cores.Add(new SolrServerElement
{
Id = "index1",
DocumentType = typeof(Index1Item).AssemblyQualifiedName,
Url = "http://localhost:8080/solr/index1",
});
cores.Add(new SolrServerElement
{
Id = "index2",
DocumentType = typeof(Index2Item).AssemblyQualifiedName,
Url = "http://localhost:8080/solr/index2",
});
var kernal = new StandardKernel(new SolrNetModule(cores));
var operations = kernal.Get<ISolrOperations<Index1Item>>("index1");
Hopefully this will help...
I have not yet used Solr but from the Module I found on github I'd say you have to assign the generic type argument to the document type instead of ISolrOperations
SolrNet has since been updated to support multiple cores of the same DocumentType with named bindings so your suspect code should work now.
I doubt anyone has specific experience related to this particular task, but maybe you can spot my problem. I'm trying to make a call to lithium (forum software) to place a vote in their poll, and their docs show this:
Example URL:
http://community.lithium.com/community-name/restapi/vc/polls/id/15/votes/place
Query Arguments:
poll.choice (required): - the choice to place the vote for. The choice is specified by a string of the form id/choice_id where choice_id is the id of the poll choice
Http Method:
POST
So my code looks something like this:
Dim _Response As New XmlDocument
Dim RestApiRoot As String = "http://example.com/community-name/restapi/vc/polls/id/6/votes/place"
APIRequest = WebRequest.Create(RestApiRoot)
APIRequest.Method = "POST"
APIRequest.Headers.Add("poll.choice", HttpContext.Current.Server.UrlEncode("id/" & _choiceID.ToString))
APIResponse = APIRequest.GetResponse()
APIReader = New StreamReader(APIResponse.GetResponseStream())
_Response.LoadXml(APIReader.ReadToEnd())
APIResponse.Close()
I'm not able to successfully register a vote and they say it's because the poll.choice param is not appearing in the header, but if I step through debugging, I see it in the Header Keys/Items just fine.
Anyone have any clue what I might be doing wrong?
I do exactly this with RestSharp, an open source REST framework. It works great with the Lithium REST API.
You're code will look something like this using RestSharp:
You'll create a class to look like the response from the Lithium API, in this case "Response". It will look like this (sorry, you'll have to translate this to VB.NET):
public class LithiumResponse
{
public string status { get; set; }
public string value { get; set; }
public string message { get; set; }
}
Now RestSharp will use that to capture the result like this:
// create the request
var request = new RestRequest();
request.Verb = Method.POST;
request.BaseUrl = "http://example.com/community-name";
// specify the action
request.Action = "restapi/vc/polls/id/6/votes/place";
// add the parameters
request.AddParameter("poll.choice", "id/" + _choiceID.ToString());
// now create a RestClient to execute the request,
// telling it to put the results in your "reponse" class
var client = new RestClient();
var lithiumresponse = client.Execute<LithiumResponse>(request);
// now you can check the status property of your class to
// see if it was successful
if (lithiumresponse.status == "success")
// you successfully placed a vote
I use RestSharp for a lot of interaction with the Lithium API and it makes it brain-dead simple. Pretty awesome library.
I am having a minor problem with WCF service proxies where the message contains List<string> as a parameter.
I am using the 'Add Service reference' in Visual Studio to generate a reference to my service.
// portion of my web service message
public List<SubscribeInfo> Subscribe { get; set; }
public List<string> Unsubscribe { get; set; }
These are the generated properties on my MsgIn for one of my web methods.
You can see it used ArrayOfString when I am using List<string>, and the other takes List<SubscribeInfo> - which matches my original C# object above.
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public System.Collections.Generic.List<DataAccess.MailingListWSReference.SubscribeInfo> Subscribe {
get {
return this.SubscribeField;
}
set {
if ((object.ReferenceEquals(this.SubscribeField, value) != true)) {
this.SubscribeField = value;
this.RaisePropertyChanged("Subscribe");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
publicDataAccess.MailingListWSReference.ArrayOfString Unsubscribe {
get {
return this.UnsubscribeField;
}
set {
if ((object.ReferenceEquals(this.UnsubscribeField, value) != true)) {
this.UnsubscribeField = value;
this.RaisePropertyChanged("Unsubscribe");
}
}
}
The ArrayOfString class generated looks like this. This is a class generated in my code - its not a .NET class. It actually generated me a class that inherits from List, but didn't have the 'decency' to create me any constructors.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.CollectionDataContractAttribute(Name="ArrayOfString", Namespace="http://www.example.com/", ItemName="string")]
[System.SerializableAttribute()]
public class ArrayOfString : System.Collections.Generic.List<string> {
}
The problem is that I often create my message like this :
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.ToList()
});
I really like the clean look this gives me.
Now for the actual problem :
I cant assign a List<string> to the Unsubscribe property which is an ArrayOfString - even though it inherits from List. In fact I cant seem to find ANY way to assign it without extra statements.
I've tried the following :
new ArrayOfString(unsubscribeFrom.ToList()) - this constructor doesn't exist :-(
changing the type of the array used by the code generator - doesn't work - it always gives me ArrayOfString (!?)
try to cast List<string> to ArrayOfString - fails with 'unable to cast', even though it compiles just fine
create new ArrayOfString() and then AddRange(unsubscribeFrom.ToList()) - works, but I cant do it all in one statement
create a conversion function ToArrayOfString(List<string>), which works but isn't as clean as I want.
Its only doing this for string, which is annoying.
Am i missing something? Is there a way to tell it not to generate ArrayOfString - or some other trick to assign it ?
Any .NET object that implements a method named "Add" can be initialized just like arrays or dictionaries.
As ArrayOfString does implement an "Add" method, you can initialize it like this:
var a = new ArrayOfString { "string one", "string two" };
But, if you really want to initialize it based on another collection, you can write a extension method for that:
public static class U
{
public static T To<T>(this IEnumerable<string> strings)
where T : IList<string>, new()
{
var newList = new T();
foreach (var s in strings)
newList.Add(s);
return newList;
}
}
Usage:
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.To<ArrayOfString>()
});
I prefer not to return generic types across a service boundary in the first place. Instead return Unsubscribe as a string[], and SubscriptionInfo as SubscriptionInfo[]. If necessary, an array can easily be converted to a generic list on the client, as follows:
Unsubscribe = new List<string>(unsubscribeFrom);
Subscribe = new List<SubscriptionInfo>(subscribeTo);
Too late but can help people in the future...
Use the svcutil and explicitly inform the command line util that you want the proxy class to be serialized by the XmlSerializer and not the DataContractSerializer (default). Here's the sample:
svcutil /out:c:\Path\Proxy.cs /config:c:\Path\Proxy.config /async /serializer:XmlSerializer /namespace:*,YourNamespace http://www.domain.com/service/serviceURL.asmx
Note that the web service is an ASP.NET web service ok?!
If you are using VS 2008 to consume service then there is an easy solution.
Click on the "Advanced..." button on the proxy dialog that is displayed when you add a Service Reference. In the Collection Type drop down you can select System.Generic.List. The methods returning List should now work properly.
(Hope this is what you were asking for, I'm a little tired and the question was a tad difficult for me to read.)