How to use WCF service with raw messages? - wcf

I'm trying to use WCF service with raw messages.
1) WCF service code:
[DataContract]
public class Person
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
public static List<Person> CreateEmployees()
{
List<Person> lstPersons = new List<Person>()
{
new Person { Id = 1, FirstName = "Andrey", LastName = "Andreyev" },
new Person { Id = 2, FirstName = "Sergey", LastName = "Sergeyev" }
};
return lstPersons;
}
[ServiceContract]
public interface ITestService
{
[OperationContract(Action = TestService.RequestAction, ReplyAction = TestService.ReplyAction)]
Message GetPersonById(Message id);
}
public class TestService : ITestService
{
public const String ReplyAction = "http://localhost:4249/Message_ReplyAction";
public const String RequestAction = "http://localhost:4249/Message_RequestAction";
public Message GetPersonById(Message id)
{
string firstName = Employees.CreateEmployees().First(e => e.Id == id.GetBody<int>()).FirstName;
Message response = Message.CreateMessage(id.Version, ReplyAction, firstName);
return response;
}
}
2) Client code:
static void Main(string[] args)
{
TestServiceClient client = new TestServiceClient();
String RequestAction = "http://localhost:4249/Message_RequestAction";
int value = 1;
Message request = Message.CreateMessage(MessageVersion.Default, RequestAction, value);
Message reply = client.GetPersonById(request);
string firstName = reply.GetBody<string>();
Console.WriteLine(firstName);
client.Close();
}
When I run the client with: int value = 1 everything works fine. But, when I use: int value = 2 I get the following error:
Error in line 1 position 276. Expecting element 'string' from namespace 'http://schemas.microsoft.com/2003/10/Serialization/'.. Encountered 'Element' with name 'Fault', namespace 'http://www.w3.org/2003/05/soap-envelope'.
At line:
string firstName = reply.GetBody<string>();
The service is started and I've added the service reference through "Add Service Reference..." in VS2008. I use .NET Framework 3.5.
I'm not sure why I'm getting this error.
Thank you in advance for help.
Goran

Well, you're getting a SOAP Fault. Try logging the message (either with Fiddler, with WCF Logging, or by just reading from Message.GetReaderAtBodyContents from the message you get from the server on the client-side), and see what the fault actually says. Make sure you turn on IncludeExceptionDetailInFaults on the server side.

Related

How to send object which contains IEnumerable via Refit on NetCore?

I have to send a request object via Refit which contains 2 IEnumerable and one string, but for some reason I can't send the object forward.
I've tried to use all the paramets from the interface. Ex: [Query(CollectionFormat.Csv)] or Multi / Pipes but no success.
I've also tried to create my own CustomUrlParameterFormatter but unfortunately here I'm stuck, because I don't see a good way to retrieve the name of the property from the object request that I'm sending.
The code for CustomUrlParameterFormatter
public class CustomUrlParameterFormatter : IUrlParameterFormatter
{
public string Format(object value, ParameterInfo parameterInfo)
{
if(value is IEnumerable enumerable)
{
var result = ToQueryString(enumerable, parameterInfo.Name);
return result;
}
return string.Empty;
}
public static string ToQueryString(IEnumerable query, string parameterName)
{
var values = query.Cast<object>().Select(ToString).ToArray();
var separator = parameterName + "=";
return values.Any() ? separator + string.Join("&" + separator, values) : "";
}
public static string ToString(object value)
{
var json = JsonConvert.SerializeObject(value).Replace("\\\"", "\"").Trim('"');
return Uri.EscapeUriString(json);
}
}
The Call from the IService that I'm using
[Get("/TestMethod")]
Task<HttpResponseMessage> TestMethod([Query]TestRequestDTO requestDTO, [Header("X-Correlation-ID")] string correlationId);
The Request object
public class TestRequestDTO
{
public IEnumerable<long> EnumOne { get; set; }
public IEnumerable<long> EnumTwo { get; set; }
public string MethodString { get; set; }
}
Also the RefitClient configuration
var refitSettings = new RefitSettings();
refitSettings.UrlParameterFormatter = new CustomUrlParameterFormatter();
services.AddRefitClient<IService>(refitSettings)
.ConfigureHttpClient(c => c.BaseAddress = new Uri(settings.Services.IService));
What I'm trying to achieve is something like
TestMethod?EnumOne =123&EnumOne =321&EnumTwo=123&EnumTwo=321&methodString=asdsaa
and instead I'm receiving other behavior
without CustomUrlParameterFormatter()
TestMethod?EnumOne=System.Collections.Generic.List`1%5BSystem.Int64%5D&EnumTwo=System.Collections.Generic.List`1%5BSystem.Int64%5D&MethodString=sdf

When i want to retrieving the image from database ,It showing me a ApplicationName and WCFService Name and Class name why?

In WCF Service I am making
[ServiceContract]
public interface IService1
{
[OperationContract]
CompositeType QuestionRetrieve(String email);
}
[DataContract]
public class CompositeType
{
private String imageName;
public string ImageName
{
get { return imageName; }
set { imageName= value; }
}
In Service1.cs
public CompositeType QuestionRetrieve(String email)
{
context = new myEntities();
Profile aProfile= new Profile();
aProfile= (from c in context.Questions
where c.QuestionId == email
select c).First();
CompositeType aCompositeType = new CompositeType();
aCompositeType.imageName= aProfile.ImageName;
return aCompositeType;
}
In Other WindowForm I tried to retrieving the value but it show me WindowApplicationName, ServiceName and Class name "CompositeType"
In WindowForm we are doing on PageLoad:
Service aService = new Service();
Label1.Text = aService.QuestionRetrieve("gh#gmail.com").ToString();
It showing me
WindowFom.Service.CompositeType
Can you tell where is my error I am working with Entity.
You're executing the ToString() of the CompositeType object. Do this in stead:
Label1.Text = aService.QuestionRetrieve("gh#gmail.com").ImageName;

WCF Data Service return Complex Type

I created a ComplexType and am returning it in a service operation as shown here:
[WebGet]
public IQueryable<ComplexAddressType> GetCityByZip(string zip)
{
List<AddressType> normalizeAddress = NormalizeAddressProcess(new AddressType
{
ZIP = zip,
}).AddressList;
return normalizeAddress.Select(x =>new ComplexAddressType
{
ZIP = x.zip,
City = x.City,
State = x.State
}).AsQueryable();
}
When I try to invoke the service operation by calling http://localhost/MyService.svc/GetCityByZip?zip='20000', the service operation invocation works and the browser displays a list of cities.
When I try to invoke the service operation by calling http://localhost/MyService.svc/GetCityByZip?zip='20000'&$top=1, the browser displays an error page.
Could you can help me?
Assuming ComplexAddressType is actually a complex type, you cannot use the $top system query option with that service operation. If you enable verbose errors per the comment above, you are likely getting back this error:
Query options $orderby, $inlinecount, $skip and $top cannot be applied to the requested resource.
To be able to use $top with the service operation, you will need to return a collection of entity types rather than complex types.
You could also just introduce another parameter to your function call, so that you can use a URL such as the following:
http://localhost:59803/ScratchService.svc/GetProfiles?startsWith='ABC'&top=2
Sample code:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace Scratch.Web
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ScratchService : DataService<ScratchContext>
{
static ScratchService()
{
Database.SetInitializer(new ScratchContextInitializer());
}
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.UseVerboseErrors = true;
}
[WebGet]
public IQueryable<User> GetUsers(int numUsers)
{
var users = new List<User>();
for (int i = 0; i < numUsers; i++)
{
users.Add(new User
{
Id = i,
Password = i.ToString(),
Username = i.ToString()
});
}
return users.AsQueryable();
}
[WebGet]
public IQueryable<Profile> GetProfiles(string startsWith, int top)
{
var profiles = new List<Profile>
{
new Profile{ DisplayName = "A", Preferences = "1" },
new Profile{ DisplayName = "AB", Preferences = "2" },
new Profile{ DisplayName = "ABC", Preferences = "3" },
new Profile{ DisplayName = "ABCD", Preferences = "4" },
new Profile{ DisplayName = "ABCDE", Preferences = "5" },
new Profile{ DisplayName = "ABCDEF", Preferences = "6" },
new Profile{ DisplayName = "ABCDEFG", Preferences = "7" }
};
return profiles.Where(p => p.DisplayName.StartsWith(startsWith)).Take(top).AsQueryable();
}
}
public class ScratchContextInitializer : DropCreateDatabaseAlways<ScratchContext>
{
}
public class ScratchContext : DbContext
{
public DbSet<User> Users { get; set; }
}
public class Profile
{
public string DisplayName { get; set; }
public string Preferences { get; set; }
}
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public Profile Profile { get; set; }
}
}
Last code will work when GetCityByZip method has 2 parameters. First one for zip and second one for top. In your case you have parameters inconsistency and wcf can't find method.

WCF Json result without name/value

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.

Attributes on a derived type not being deserialized in a WCF client even though KnownType is used

I have the following types:
public enum MyEnum
{
Value1,
Value2
}
[DataContract]
public class Configuration
{
[DataMember]
public MyEnum MyValue { get; set; }
[DataMember]
public Credentials CredentialValues { get; set; }
}
[DataContract, KnownType(typeof(CustomCredentials))]
public class Credentials
{
}
[DataContract]
public class CustomCredentials : Credentials
{
[DataMember]
public string Property1 { get; set; }
[DataMember]
public string Property2 { get; set; }
}
And on my service interface, I have a function that returns an instance of Configuration with its CredentialValues property set to a fully populated instance of CustomCredentials. I receive no errors from the client or the server, but while the data is being property serialized on the server and received by the client, the properties on CustomCredentials never have a value. What do I need to change here in order to have these properties properly deserialized on the client?
For reference, the connection between client and server is made with a DuplexChannelFactory over a NetTcpBinding using a data/service contract project that is shared by the client and service applications (the service is self-hosted), so there are no service proxy types that could need to be regenerated.
Added this code to the Contracts project along with your DataContracts.
[ServiceContract(Namespace = "http://schemas.platinumray.com/duplex", SessionMode = SessionMode.Required, CallbackContract = typeof(IService1Callback))]
public interface IService1
{
[OperationContract(IsOneWay = true)]
void GetData();
}
public interface IService1Callback
{
[OperationContract(IsOneWay = true)]
void SetData(Configuration config);
}
Created the service.
public class Service1 : IService1
{
public void GetData()
{
var x = new Configuration()
{
MyValue = MyEnum.Value1,
CredentialValues = new CustomCredentials { Property1 = "Something", Property2 = "Something else" }
};
OperationContext.Current.GetCallbackChannel<IService1Callback>().SetData(x);
}
}
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost( typeof(Service1), new Uri[] { new Uri("net.tcp://localhost:6789") }))
{
host.AddServiceEndpoint(typeof(IService1), new NetTcpBinding(), "Service1");
host.Open();
Console.ReadLine();
host.Close();
}
}
}
Created the client.
public class CallbackHandler : IService1Callback
{
public void SetData(Configuration config)
{
Console.WriteLine(config.CredentialValues.GetType().Name);
Console.WriteLine(((CustomCredentials)config.CredentialValues).Property1);
Console.WriteLine(((CustomCredentials)config.CredentialValues).Property2);
}
}
class Program
{
static void Main(string[] args)
{
// Setup the client
var callbacks = new CallbackHandler();
var endpoint = new EndpointAddress(new Uri("net.tcp://localhost:6789/Service1"));
using (var factory = new DuplexChannelFactory<IService1>(callbacks, new NetTcpBinding(), endpoint))
{
var client = factory.CreateChannel();
client.GetData();
Console.ReadLine();
factory.Close();
}
}
}
Outputs the following as expected:
CustomCredentials
Something
Something else
So this actually worked without modifying any of your data contracts... The same results if I revert to a twoway operation and just return Configuration directly without using the callback.
Also tried making Credentials abstract but could not replicate your problem.
Have I missed something?