I have a method like this
[WebInvoke(UriTemplate = "StrDetails", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
public List<StrSearchDetails> StrDetails(string str1)
{
List<StrSearchDetails> details = new List<StrSearchDetails> ();
return details;
}
I am able to hit this method from Fiddler
I have updated and replaced like this
[WebInvoke(UriTemplate = "StrDetails", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
public List<StrSearchDetails> StrDetails(string str1, string str2)
{
List<StrSearchDetails> details = new List<StrSearchDetails> ();
return details;
}
Not able to hit this method. Throwing 500 error in Fiddler.
Any thoughts?
Try changing the uri template:
[WebInvoke(uriTemplate="/StrDetails?str1={str1}&str2={str2}", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
Related
I am trying to use the Ninject Dependency Injection to bind a callback method to WCF REST services runs in a kind of plugin module of a software system, which is NOT possible to use the SVC file or webconfig or app.config for any configuration.
The interface and implementation of the WCF services are defined as below:
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
string DoWork();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService1
{
private IEventCallback EventCallback { get; set; }
public Service1(IEventCallback eventCallback)
{
EventCallback = eventCallback;
}
public string DoWork()
{
if (EventCallback != null)
{
EventCallback.Send("Testing Event ID");
}
return "Success";
}
}
where the IEventCallback and the corresponding implementation are defined as below:
public interface IEventCallback
{
void Send(string eventId);
}
public class EventCallback : IEventCallback
{
private Action<string> OnSendCustomEventCallBack { get; set; }
public EventCallback(Action<string> onSendCustomEventCallBack)
{
OnSendCustomEventCallBack = onSendCustomEventCallBack;
}
public void Send(string eventId)
{
if (OnSendCustomEventCallBack != null)
{
OnSendCustomEventCallBack(eventId);
}
}
}
The codes to create the REST Service are as below:
public AuthenticatedWebServiceHost(Type type, Uri url, string authenUsername, string authenPassword)
{
AuthenUsername = authenUsername;
AuthenPassword = authenPassword;
IDictionary<string, ContractDescription> desc;
InitializeDescription(type, new UriSchemeKeyedCollection());
base.CreateDescription(out desc);
var val = desc.Values.First();
var binding = new WebHttpBinding();
binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
Credentials.UserNameAuthentication.CustomUserNamePasswordValidator =
new CustomUserNamePasswordValidator(AuthenUsername, AuthenPassword);
AddServiceEndpoint(val.ContractType, binding, url);
}
And, the AuthenticatedWebServiceHost is called as below:
var eventCallback = new EventCallback(OnSendCustomEventCallBack); // where OnSendCustomEventCallBack is a defined method
// How to write codes to use Ninject to inject the callback into the Service?
// kernel.Bind<IEventCallback>().To<??>()
_webServiceHost = new AuthenticatedWebServiceHost(typeof(Service1), new Uri("http://localhost:9000/Events"),
"admin", "password");
_webServiceHost.Open();
Since, no XML configuration is allowed in my case, how to write codes to use Ninject to bind the callback to the WCF Services?
I eventually figured out the solution by referencing Is it possible to instantiate a WebServiceHost via an instance of the service type, without a parameterless constructor? without using NInject.
I have a struggling time with WCF REST to parse request body.
My problem:
POST method https://{Service}/X/Y? Z= 0000000
Body Request: {"id":"id"}
My code:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/X/{y}?Z={z}")
]
string GetRequest(string y, string z, Request request);
}
public class Service : IService
{
public string GetRequest(string y, string z, Request request)
{
//Do sth
}
[DataContract]
public class Request
{
[DataMember]
[JsonProperty("id")]
public String Id { get; set; }
}
The problem that I have is that y and z has data and they are correct BUT id in request is null. I expected to be "id".
I searched a lot in the internet and I found Stream solution which is not easily to follow in this case.
I am wondering if anyone has a clever idea to do this.
Take a look on this version
The Service
namespace ServiceTest
{
internal class Program
{
private static WebServiceHost _service;
private static void Main()
{
_service = new WebServiceHost(typeof (Service));
Console.WriteLine("The service has started");
_service.Open();
Console.ReadKey();
}
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public sealed class Service : IService
{
public string GetRequest(string y, string z, Request request)
{
Console.WriteLine("Y: {0}, Z: {1}, request: {2}", y, z, request);
return "Ok";
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json, UriTemplate = "/X/{y}?Z={z}")]
string GetRequest(string y, string z, Request request);
}
[DataContract]
public sealed class Request
{
[DataMember]
public string Id { get; set; }
public override string ToString()
{
return string.Format("Id: {0}", Id);
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="ServiceTest.Service">
<host>
<baseAddresses>
<add baseAddress="http://localhost:9090/webhost" />
</baseAddresses>
</host>
<endpoint binding="webHttpBinding" contract="ServiceTest.IService" />
</service>
</services>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
The Client
internal class Program
{
private static void Main(string[] args)
{
var client = new HttpClient();
var request = new Request {Id = "Nelibur"};
var result = client.PostAsync("http://localhost:9090/webhost/X/Y?Z=2000", CreateContent(request)).Result;
Console.WriteLine(result.Content.ReadAsStringAsync().Result);
Console.ReadKey();
}
private static StringContent CreateContent<T>(T value)
{
using (var stream = new MemoryStream())
{
var serializer = new DataContractJsonSerializer(typeof (T));
serializer.WriteObject(stream, value);
string content = Encoding.UTF8.GetString(stream.ToArray());
return new StringContent(content, Encoding.UTF8, "application/json");
}
}
}
Raw request:
POST http://localhost:9090/webhost/X/Y?Z=2000 HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: localhost:9090
Content-Length: 16
Expect: 100-continue
Connection: Keep-Alive
{"Id":"Nelibur"}
You can try to use the request in for example Fiddler
Since Wcf REST do not support Out parameter .Then how can I get the value from the method that is retuning the value.
[OperationContract(IsOneWay = false)]
[WebInvoke
(Method = "GET",
ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "xml/getcommentsforvideopage?vid={videoID}&psize={pageSize}&pnum={pageNumber}")]
IEnumerable<DTOUserComment> GetCommentsForVideoPage(
// out int resultCount,
int videoID, string pageSize,
string pageNumber);
Implemented as this below------------------
public IEnumerable<DTOUserComment> GetCommentsForVideoPage(
int videoID, string pageSize,
string pageNumber)
{
int? pageSizeInt = pageSize.ParseNullableInt();
int? pageNumberInt = pageNumber.ParseNullableInt();
IEnumerable<DTOUserComment> results = null;
// TODO
int resultCount;
try
{
results = searcher.GetCommentsForVideoPage(**out resultCount,** videoID, pageSizeInt, pageNumberInt);
}
catch (UnauthorizedAccessException ex)
{
Logger.Write(ex);
}
catch (Exception ex)
{
Logger.Write(ex);
}
return results;
}
Client Side I am consuming using HttpClient--
public IEnumerable<UserComment> CommentsPage(int videoId, int startRowIndex, int maximumRows)
{
int pageSize = maximumRows;
if (maximumRows < 1) { maximumRows = 1; }
int startingPage = (startRowIndex / maximumRows) + 1;
using (var client = new HttpClient())
{
HttpResponseMessage response = client.GetAsync("http://localhost:25252/MyRESTService.svc/xml/getcommentsforvideopage?vid=" + videoId + "&psize=" + pageSize + "&pnum=" + startingPage).Result;
string strJson = response.Content.ReadAsStringAsync().Result;
JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var data = JObject.Parse(strJson)["GetCommentsForVideoPageResult"];//JSON array starts with "GetCommentsForVideoPageResult"
IEnumerable<UserComment> comments = JsonConvert.DeserializeObject<IEnumerable<UserComment>>(data.ToString(),settings);
return comments;
}
}
Do these things.
1.Create a wrapper class like this
public class WrappedDTOUserComment
{
public IEnumerable<DTOUserComment> Comments { get; set; }
public int CommentCount { get; set; }
}
2.Then change the method like this
public WrappedDTOUserComment GetCommentsForVideoPage(
int videoID, string pageSize,
string pageNumber)
{
int? pageSizeInt = pageSize.ParseNullableInt();
int? pageNumberInt = pageNumber.ParseNullableInt();
WrappedDTOUserComment data = null;
IEnumerable<DTOUserComment> results = null;
// TODO
int resultCount;
try
{
results = searcher.GetCommentsForVideoPage(**out resultCount,** videoID, pageSizeInt, pageNumberInt);
}
catch (UnauthorizedAccessException ex)
{
Logger.Write(ex);
}
catch (Exception ex)
{
Logger.Write(ex);
}
data.Comments = results;
data.CommentCount = resultCount;
return data;
}
3.The interface will be
[OperationContract(IsOneWay = false)]
[WebInvoke
(Method = "GET",
ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "xml/getcommentsforvideopage?vid={videoID}&psize={pageSize}&pnum={pageNumber}")]
WrappedDTOUserComment GetCommentsForVideoPage(
// out int resultCount,
int videoID, string pageSize,
string pageNumber);
why is the parameter of my WCF Rest service method always null?....I do access the service's method and i do get the string returned by the wcf method, but the parameter remains null.
Operation Contract:
[OperationContract]
[WebInvoke(UriTemplate = "AddNewLocation",
Method="POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
string AddNewLocation(NearByAttractions newLocation);
Implementation of AddNewLocation method
public string AddNewLocation(NearByAttractions newLocation)
{
if (newLocation == null)
{
//I'm always getting this text in my logfile
Log.Write("In add new location:- Is Null");
}
else
{
Log.Write("In add new location:- " );
}
//String is returned even though parameter is null
return "59";
}
Client code:
WebClient clientNewLocation = new WebClient();
clientNewLocation.Headers[HttpRequestHeader.ContentType] = "application/json";
JavaScriptSerializer js = new JavaScriptSerializer();
js.MaxJsonLength = Int32.MaxValue;
//Serialising location object to JSON
string serialLocation = js.Serialize(newLocation);
//uploading JSOn string and retrieve location's ID
string jsonLocationID = clientNewLocation.UploadString(GetURL() + "AddNewLocation", serialLocation);
I also tried this code in my client but still get a null parameter
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(NearByAttractions));
MemoryStream ms = new MemoryStream();
ser.WriteObject(ms, newLocation);
String json = Encoding.UTF8.GetString(ms.ToArray());
WebClient clientNewLocation = new WebClient();
clientNewLocation.Headers[HttpRequestHeader.ContentType] = "application/json";
string r = clientNewLocation.UploadString(GetURL() + "AddNewLocation", json);
Console.Write(r);
Then i also changed the BodyStyle option to "Bare" but then I got the following error (with both client codes):
The remote server returned an error: (400) Bad Request.
Any help please? thanks
Edit 1:
My GetUrl() method loads the web service IP address from the web config file and returns an object of type Uri
private static Uri GetURL()
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~/web.config");
string sURL = config.AppSettings.Settings["serviceURL"].Value;
Uri url = null;
try
{
url = new Uri(sURL);
}
catch (UriFormatException ufe)
{
Log.Write(ufe.Message);
}
catch (ArgumentNullException ane)
{
Log.Write(ane.Message);
}
catch (Exception ex)
{
Log.Write(ex.Message);
}
return url;
}
service address stored in web config as follows:
<appSettings>
<add key="serviceURL" value="http://192.168.2.123:55666/TTWebService.svc/"/>
</appSettings>
This is how my NearByAttraction class defined
[DataContractAttribute]
public class NearByAttractions
{
[DataMemberAttribute(Name = "ID")]
private int _ID;
public int ID
{
get { return _ID; }
set { _ID = value; }
}
[DataMemberAttribute(Name = "Latitude")]
private string _Latitude;
public string Latitude
{
get { return _Latitude; }
set { _Latitude = value; }
}
[DataMemberAttribute(Name = "Longitude")]
private string _Longitude;
public string Longitude
{
get { return _Longitude; }
set { _Longitude = value; }
}
You seem to be in the right track. You need the Bare body style, otherwise you'd need to wrap the serialized version of your input in another JSON object. The second code should work - but without more information about how the service is set up and what GetURL() returns we can only guess.
One way to find out what to send to a WCF REST service is to use a WCF client itself for that - using the WebChannelFactory<T> class, then use a tool such as Fiddler to see what it's sending. The example below is a SSCCE which shows your scenario working.
public class StackOverflow_15786448
{
[ServiceContract]
public interface ITest
{
[OperationContract]
[WebInvoke(UriTemplate = "AddNewLocation",
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
string AddNewLocation(NearByAttractions newLocation);
}
public class NearByAttractions
{
public double Lat { get; set; }
public double Lng { get; set; }
public string Name { get; set; }
}
public class Service : ITest
{
public string AddNewLocation(NearByAttractions newLocation)
{
if (newLocation == null)
{
//I'm always getting this text in my logfile
Console.WriteLine("In add new location:- Is Null");
}
else
{
Console.WriteLine("In add new location:- ");
}
//String is returned even though parameter is null
return "59";
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
Console.WriteLine("Using WCF-based client (WebChannelFactory)");
var factory = new WebChannelFactory<ITest>(new Uri(baseAddress));
var proxy = factory.CreateChannel();
var newLocation = new NearByAttractions { Lat = 12, Lng = -34, Name = "56" };
Console.WriteLine(proxy.AddNewLocation(newLocation));
Console.WriteLine();
Console.WriteLine("Now with WebClient");
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(NearByAttractions));
MemoryStream ms = new MemoryStream();
ser.WriteObject(ms, newLocation);
String json = Encoding.UTF8.GetString(ms.ToArray());
WebClient clientNewLocation = new WebClient();
clientNewLocation.Headers[HttpRequestHeader.ContentType] = "application/json";
string r = clientNewLocation.UploadString(baseAddress + "/AddNewLocation", json);
Console.WriteLine(r);
}
}
Solved and thank you
I changed BodyStyle to "Bare" So my serivce interface is as follows:
[OperationContract]
[WebInvoke(UriTemplate = "AddNewLocation",
Method="POST",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
string AddNewLocation(NearByAttractions newLocation);
Then implemented my client as follows:
MemoryStream ms = new MemoryStream();
DataContractJsonSerializer serialToUpload = new DataContractJsonSerializer(typeof(NearByAttractions));
serialToUpload.WriteObject(ms, newLocation);
WebClient client = new WebClient();
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
client.UploadData(GetURL() + "AddNewLocation", "POST", ms.ToArray());
I used WebClient.UploadData instead of UploadString.
I created a WCF service to return JSON, however, it is not returned in the way i need it.
My interface:
[ServiceContract]
public interface IService1
{
[OperationContract(Name="Sensors")]
[WebInvoke(
Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "test")]
List<Sensor> testdata();
}
My service:
public class Service1 : IService1
{
public List<Sensor> testdata()
{
return HamsData.GetSensorDetails("1");
}
}
HamsData.GetSensorDetails:
public static List<Sensor> GetSensorDetails(string id)
{
List<Sensor> al = new List<Sensor>();
DateTime now = DateTime.Now;
DateTime thishour = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
using ( HAMSDataClassesDataContext db = new HAMSDataClassesDataContext())
{
var dbsensors = (from p in db.sensordetails where p.sensorlatestdate == thishour select new Sensor { name = p.sensor.name, value = p.sensorlatestvalue });
foreach (Sensor x in dbsensors)
{
al.Add(x);
}
return al;
}
}
The Sensor class:
[Serializable]
[DataContract(Name = "mysensor")]
public class Sensor
{
[DataMember]
public string name { get; set; }
[DataMember]
public decimal value { get; set; }
}
This return the following JSON:
[{"name":"EIC","value":1000.000},{"name":"GIC","value":0.000},{"name":"WIC","value":0.000},{"name":"EHC","value":0.010},{"name":"GHC","value":0.000},{"name":"WHC","value":0.000},{"name":"EDC","value":33458.560},{"name":"ENC","value":27450.040},{"name":"GRC","value":35227.100},{"name":"WRC","value":38.390},{"name":"ECR","value":1.000},{"name":"10:D8:A2:DC:01:08:00:E0:T","value":24.120},{"name":"10:94:3D:B4:01:08:00:BC:T","value":46.310},{"name":"10:31:85:70:01:08:00:4D:T","value":20.940},{"name":"10:5D:5E:B4:01:08:00:EA:T","value":7.690},{"name":"10:DD:56:B4:01:08:00:3E:T","value":17.690},{"name":"28:51:32:5D:02:00:00:0A:T","value":12.560},{"name":"26:B1:08:81:00:00:00:39:T","value":15.030},{"name":"26:B1:08:81:00:00:00:39:H","value":-29.890},{"name":"26:CD:A0:6D:00:00:00:8A:T","value":15.030},{"name":"26:CD:A0:6D:00:00:00:8A:L","value":204.600}]
However, I want it without the name and value tags like:
[{"EIC":1000.000},{"GIC":0.000},{"WIC":0.000},{"EHC":0.010},{"GHC":0.000},{"WHC":0.000},{"EDC":33458.560},{"ENC":27450.040},{"GRC":35227.100},{"WRC":38.390},{"ECR":1.000},{"10:D8:A2:DC:01:08:00:E0:T":24.120},{"10:94:3D:B4:01:08:00:BC:T":46.310},{"10:31:85:70:01:08:00:4D:T",e":20.940},{"10:5D:5E:B4:01:08:00:EA:T":7.690},{"10:DD:56:B4:01:08:00:3E:T":17.690},{"28:51:32:5D:02:00:00:0A:T"12.560},{"26:B1:08:81:00:00:00:39:T":15.030},{"26:B1:08:81:00:00:00:39:H":-29.890},{"26:CD:A0:6D:00:00:00:8A:T":15.030},{"26:CD:A0:6D:00:00:00:8A:L":204.600}]
Can someone tell what i'm doing wrong here?
Thats not json, thats the problem. Json encoding is a combination of property/value. You are trying to misuse it.
Are you really sure you want to encode the data that way? It makes it far hard to extract the values.