WCF Rest Links
Here are some links that I've used to find information about working with REST services. I've deviated from these as I've learned things, however these are great starting points.
I hope you all enjoyed the talk and found the session useful.
Here are a couple of snippets of code to refresh. From the Service Interop:
And from the Response Behaviors. Use these classes to build the layer that is used to send requests to the service:
And finally, a sample of how we queried to the route in the Crud Utility. This should be enough to fill in the blanks from setup to the part where the service is querying the database, which is reviewed in the previous post. Obviously, the pubs database has different objects so if you wanted to use that database a new Datacontract object would need to be created for each type you want to serialize.
Also, I've just realized that the original post never had any invokes to send data to the service, so here is an example from insert:
Also, here is a method from the JSON enabled service we built at the very end:
Hopefully I'll get something more formal out here soon! Enjoy!
The Web Consumer from our talk on App Harbor (warning: as this has no security I cannot guarantee that someone hasn't posted text that may be offensive to others).
An eariler entry in this blog covered setting up the first service (using stored procedures). It is a good starting point, however is very incomplete and I highly recommend making the push to move towards Linq-To-SQL or entities like we discussed in the session today.
I hope you all enjoyed the talk and found the session useful.
Here are a couple of snippets of code to refresh. From the Service Interop:
public class ServiceInterop
{
IResponseBehavior _rb;
public ServiceInterop(IResponseBehavior rb)
{
_rb = rb;
}
public T QueryServiceForDataContract<T>(string url, string uri)
{
if (typeof(DataContractResponseBehavior<T>).Equals(_rb.GetType()))
{
return queryService(url, uri, null, null, null, true);
}
else
{
throw new Exception("Type did not match for generic get data contract method in ServiceAdapter.ServiceInterop");
}
}
public dynamic QueryServiceDefault(string url, string uri)
{
return queryService(url, uri, null, null, null, false);
}
public dynamic QueryServiceUsingQueryStringVariables(string url, string uri, HttpQueryString hqs)
{
return queryService(url, uri, hqs, null, null, false);
}
public dynamic QueryServiceUsingXElement(string url, string uri, XElement xElm)
{
return queryService(url, uri, null, xElm, null, false);
}
public dynamic QueryServiceUsingXDocument(string url, string uri, XDocument xDoc)
{
return queryService(url, uri, null, null, xDoc, false);
}
private dynamic queryService(string url, string uri, HttpQueryString hqs, XElement xElm, XDocument xDoc, bool IsDataContract)
{
using (HttpClient client = new HttpClient(url))
{
if (null != hqs)
{
using (HttpResponseMessage res = client.Get(new Uri(uri, UriKind.Relative), hqs))
{
res.EnsureStatusIsSuccessful();
return _rb.getResponse(res);
}
}
else if (null != xElm)
{
client.DefaultHeaders.Add("Content-Type", "application/xml; charset=utf-8");
using (HttpResponseMessage res = client.Post(uri, HttpContent.Create(xElm.ToString(SaveOptions.DisableFormatting))))
{
res.EnsureStatusIsSuccessful();
return _rb.getResponse(res);
}
}
else if (null != xDoc)
{
client.DefaultHeaders.Add("Content-Type", "application/xml; charset=utf-8");
using (HttpResponseMessage res = client.Post(uri, HttpContent.Create(xDoc.ToString(SaveOptions.DisableFormatting))))
{
res.EnsureStatusIsSuccessful();
return _rb.getResponse(res);
}
}
else if (IsDataContract)
{
client.DefaultHeaders.Add("Content-Type", "application/xml; charset=utf-8");
using (HttpResponseMessage res = client.Get(new Uri(uri, UriKind.Relative)))
{
//ensure response is successful
res.EnsureStatusIsSuccessful();
return _rb.getResponse(res);
}
}
else
{
using (HttpResponseMessage res = client.Get(new Uri(uri, UriKind.Relative)))
{
res.EnsureStatusIsSuccessful();
return _rb.getResponse(res);
}
}
}
}
}
And from the Response Behaviors. Use these classes to build the layer that is used to send requests to the service:
//Response Behaviors
namespace ServiceAdapter
{
public interface IResponseBehavior
{
dynamic getResponse(HttpResponseMessage res);
}
///
/// Return response as Dataset
///
public class DatasetResponseBehavior : IResponseBehavior
{
public dynamic getResponse(HttpResponseMessage res)
{
StreamReader sr = new StreamReader(res.Content.ReadAsStream());
DataSet ds = new DataSet();
ds.ReadXml(sr);
return ds;
}
}
///
/// Return response as String
///
public class ScalarStringResponseBehavior : IResponseBehavior
{
public dynamic getResponse(HttpResponseMessage res)
{
//ReadAsXelement requires Extensions reference.
XElement elm = res.Content.ReadAsXElement();
return elm.Value;
}
}
///
/// Return response as a Boolean
///
public class ScalarBooleanResponseBehavior : IResponseBehavior
{
public dynamic getResponse(HttpResponseMessage res)
{
//ReadAsXelement requires Extensions reference.
XElement elm = res.Content.ReadAsXElement();
string v = elm.Value;
if (v.ToUpper().Equals("TRUE"))
{
return true;
}
else
{
return false;
}
}
}
///
/// Return response as an integer
///
public class ScalarIntResponseBehavior : IResponseBehavior
{
public dynamic getResponse(HttpResponseMessage res)
{
//ReadAsXelement requires Extensions reference.
XElement elm = res.Content.ReadAsXElement();
string v = elm.Value;
return Convert.ToInt32(v);
}
}
///
/// Return response read as a specific data contract type.
///
public class DataContractResponseBehavior<T> : IResponseBehavior
{
public dynamic getResponse(HttpResponseMessage res)
{
return res.Content.ReadAsDataContract<T>();
}
}
}
And finally, a sample of how we queried to the route in the Crud Utility. This should be enough to fill in the blanks from setup to the part where the service is querying the database, which is reviewed in the previous post. Obviously, the pubs database has different objects so if you wanted to use that database a new Datacontract object would need to be created for each type you want to serialize.
public DataContracts.ErrorDataList GetAllErrors()
{
string serviceURI = "xml/errors";
IResponseBehavior rb = new DataContractResponseBehavior();
ServiceInterop si = new ServiceInterop(rb);
return si.QueryServiceForDataContract<DataContracts.ErrorDataList>(this.BaseServiceURL,serviceURI);
}
Also, I've just realized that the original post never had any invokes to send data to the service, so here is an example from insert:
//from the interface class that defined methods:
//admin/errors/InsertError
[WebInvoke(Method = "POST", UriTemplate = "admin/errors/InsertError")]
[OperationContract]
bool InsertError(ErrorServiceInterop.DataContracts.ErrorData ed);
//...
//And the class code for invoke...
/// Insert a new error
public bool InsertError(ErrorServiceInterop.DataContracts.ErrorData ed)
{
ErrorTrackingLog etl = new ErrorTrackingLog
{
//ID = ed.ErrorLogID -- no. this is identity.
ApplicationID = ed.ApplicationID
,userName = ed.UserName
,className = ed.ClassName
,methodName = ed.MethodName
,errorTime = ed.ErrorTime
,errorMessage = ed.ErrorMessage
,errorTrace = ed.ErrorTrace
};
_context.ErrorTrackingLogs.InsertOnSubmit(etl);
_context.SubmitChanges();
return true;
}
Also, here is a method from the JSON enabled service we built at the very end:
//json/errors/{appid}
[OperationContract]
[WebGet(UriTemplate = "json/errors/{appid}")]
ErrorServiceInterop.DataContracts.ErrorDataList GetErrorsByApplicationID(string appid)
{
int appID = Convert.ToInt32(appid);
ErrorServiceInterop.DataContracts.ErrorDataList edl = new ErrorServiceInterop.DataContracts.ErrorDataList();
List<ErrorServiceInterop.DataContracts.ErrorData> errors = new List<ErrorServiceInterop.DataContracts.ErrorData>();
var appErrors = from x in _context.ErrorTrackingLogs where x.ApplicationID == appID select x;
foreach (ErrorTrackingLog etl in appErrors)
{
errors.Add(GetEDContractFromEDContext(etl));
}
edl.Errors = errors;
return edl;
}
Hopefully I'll get something more formal out here soon! Enjoy!
I just updated the post replacing some reserved chars with their appropriate HTML rendering. If you see anything off track, it may be because it was wrapped in greater than or less than signs and needs to be updated. Please let me know if I missed one or more of the characters.
ReplyDelete