I'm currently in the process of writing a UWP application. I'm using a WCF Service to talk to a Business Layer that contains EF to talk to the SQL Server database. It's all in the very early stages as I've never used UWP before.
I got the UWP to consume the WCF to return data from the DB. This was working fine when I returned a string. However, now that I want to return objects this is no longer working in the sense that UWP just receives a reference. No object is returned. When I run the WCF in debug mode, the object is returned and I can see all the fields with data etc.
Could one of you geniuses help me, as I'm stuck and don't know what to do.
Here is my code. My class in Business Layer
namespace Business.Models
{
[DataContract(IsReference = true)]
public class SystemUser
{
public tblSystemUser User { get; set; }
// public tblRole Role { get; set; }
}
}
WCF code:
namespace ActiveCareWCF
{
[ServiceContract]
public interface IUser
{
[OperationContract]
Task<SystemUser> DoLogin(string userName);
}
public class Service : IUser
{
public async Task<SystemUser> DoLogin(string userName)
{
SystemUser systemUser = new SystemUser();
userName = #"username";
try
{
ServiceCalls serviceCalls = new ServiceCalls();
systemUser = serviceCalls.AuthorizeUser(userName);
return systemUser --- **this is returning an object**;
}
catch (Exception ex)
{
throw ex;
}
}
}
The SVC file:
public class ActiveCareService : IUser
{
public async Task<SystemUser> DoLogin(string userName)
{
Service service = new Service();
var user = service.DoLogin(userName);
return user.Result;
}
}
And finally the call in UWP.
private async void Login_Click(object sender, RoutedEventArgs e)
{
ActiveCareService.UserClient client = new ActiveCareService.UserClient();
var userFromService = client.DoLoginAsync(#"username").Result;
await client.CloseAsync();
var dialog = new MessageDialog("Logged in as " + userFromService.FirstName); **This just returns a string of the type of object it is, not the actual object. This is what I'm struggling with.**
await dialog.ShowAsync();
Frame.Navigate(typeof(YourSites));
}
Thanks in advance.
I'm doing the same thing, for now my services always return JSON strings, it means must serialize in service and deserialize at uwp.
You must have the model of serialized classes both at service and UWP. It works pretty well.
At My service I have a full Model and at UWP app I create a reduced model that matches with my needs.
Hope this can help.
Related
My goal is to call api (via post), accept payload as base type and later cast it to concrete type. If I do that from main solution (where my api stands), everything works well. But I can't understand why same code doesn't work from other solutions.
So I have my request (declared in different solutions)
namespace Nb
{
public class NbRequestBase
{
public string BaseProp { get; set; }
}
public class NbRequestConcrete : NbRequestBase
{
public string ConcreteProp { get; set; }
}
}
And this is my endpoint:
[HttpPost]
[Route("payments/nb")]
public IHttpActionResult Prepare(NbRequestBase request)
{
if(request is NbRequestConcrete)
{
}
try
{
// <<< INSERT CODE HERE >>>
NbRequestConcrete nbRequestConcrete = (NbRequestConcrete)request;
return Ok();
}
catch (Exception ex)
{
_logger.Error(ex);
return InternalServerError();
}
}
and this is my calling code:
NbRequestConcrete requestTwo = new NbRequestConcrete()
{
BaseProp = "BaseProp",
ConcreteProp = "ConcreteProp"
};
using (var client = new HttpClient())
{
var _clientId = "_clientId";
var _clientSecret = "_clientSecret";
client.BaseAddress = new Uri("http://localhost:50228");
#region Formatter
JsonMediaTypeFormatter formatter = new JsonMediaTypeFormatter();
formatter.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
List<MediaTypeFormatter> formatters = new List<MediaTypeFormatter>();
formatters.Add(formatter);
#endregion
var responseMessage = client.PostAsync($"payments/nb?clientId={_clientId}&clientSecret={_clientSecret}", requestTwo, formatter).Result;
responseMessage.EnsureSuccessStatusCode();
}
If I put my calling code into other project/solution (for example just new console app), API endpoint is hit, but payload is null.
payload when called form console app
If I put exacly same calling code into project where my api is (for example in same API endpoint method, at try/catch block start and call it again), API endpoint is hit, payload is NOT null and casting works. Why is it? And how to fix it?
payload when called from same solution try/catch start
And BTW. How to make this call via postman?
Regards
This line tells the model binder to set the values of any matching properties in request to the value that was passed to the API:
public IHttpActionResult Prepare(NbRequestBase request)
The model binder does not attach all the other properties to the request, because it has no idea what they would be.
Problem was Assemblies name where NbRequestConcrete in console app lived in one assembly and on API lived in other. So request was different.
{
"$type": "Nb.NbRequestConcrete, Tester",
"ConcreteProp": "ConcreteProp",
"BaseProp": "BaseProp"
}
VS
{
"$type": "Nb.NbRequestConcrete, MYApi",
"ConcreteProp": "ConcreteProp",
"BaseProp": "BaseProp"
}
I have a clean architecture project that provide micro services, one of which is to access Agresso ERP web services.
https://***************/service.svc
it provide many services
https://**/service.svc?FooService/Foo
https://**/service.svc?BooService/Boo
each of which has it's own service reference(connected service), and each of which has many methods.
each call to any of the end point you need to pass credentials with it.
var fooSoapClient = new FooSoapClient();
var credentials = new WSCredentials
{
Username = "fakeuser",
Password = "fakepassword",
Client = "fakeclient",
};
var result = fooSoapClient.GetFoosAsync(Foo filter,true,
credentials );
(P.S) credential class exist in all entities
namespace Foo1NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
namespace Foo2NS
{
public partial class WSCredentials : object
{
public string Username {get;set;}
public string Client {get;set;}
public string Password {get;set;}
}
}
i can access all end points with no problem.
I have the following Questions:
Is there a generic solution i can follow for not to Fall in DRY?
is there a design pattern that best target this issue?
Here is what I've done in the past, it fits in well into Dependency Injection/containers if you use that as well. The key thing here is to define an single interface that all services will implement. Your code that uses this should only be using the interface.
Each class should implement an interface you define, e.g. IWebServiceOperations
public interface IWebServiceOperations
{
WebServiceOperationResult GetFooAsync(WebServiceOperationRequest request);
}
I'll leave you to figure out the classes WebServiceOperationResult/Request, they just hold your request/response variables, including credentials.
Then each webservice you need to implement is done in a separate class. You also dictate in the constructor what type of implementation this is (FooSoap1 vs FooSoap2) e.g.
public class FooSoapClient : BaseClient, IWebServiceOperations
{
public FooSoapClient() : base(Clients.FooSoap1)
public GetFooAsync(...)
{
...
}
}
public class BaseClient
{
private readonly eFooServiceType _serviceType;
public eFooServiceType ServiceType {
get{
return _serviceType;
}
}
protected BaseClient(eFooServiceType service)
{
_serviceType = service;
}
}
Now you should have a bunch of class references. Either your DI container can resolve these for you, based on the service type you want, or you could add them to a Dictionary, so if you wanted to operate against FooSoap1, you'd do...
var fooSoapClient1 = myServices[Clients.FooSoap1];
await fooSoapClient1.GetFooAsync(...)
I have a working service in 4.0.31 that looks like this:
public object Post(MyDTO request)
{
foreach (var uploadedFile in base.Request.Files)
{
... do something ...
}
return new MyDTOResponse();
}
Everything works great, and I'm happy!
But now, I want to call the same service method from within another service, the way to do this apparently is:
public object Post(MyOtherDTO request)
{
var myService = base.ResolveService<MyService>();
// now I call some new method I wrote to bypass the file upload part, since
// myService.Post() doesn't know about the file upload part
var myResponse = myService.NewMethodThatLetsMePassAStreamToTheOtherService(streamData);
... do other stuff...
return new MyOtherDTOResponse();
}
While I'm not unhappy with this, it does create a hard dependency between the two services, so I'm not thrilled like I usually am with ServiceStack!
Is there a more elegant way of putting this together? I'm probably just missing something really, really obvious...
I'm not 100% clear on what the issue is, if it's how to share logic between services? then you could pull common logic out of each service class and reference the shared code in both Services.
If no dependencies are required I'll refactor the shared code behind re-usable extension methods.
If dependencies are required I will refactor it behind a shared logic class that's a dependency in both Services, see the IGreeter example in the sharing logic between MVC and ServiceStack answer:
public class MyService1 : Service
{
public ISharedDep SharedDep { get; set]
public object Any(Request1 request)
{
//...
}
}
public class MyService2 : Service
{
public ISharedDep SharedDep { get; set]
public object Any(Request2 request)
{
//...
}
}
Shared logic using Request Context using base class
If it's common code used by many Services that requires the base.Request context than you could move it to a common Service base class:
public class MyServiceBase : Service
{
public ISharedDep SharedDep { get; set]
public object SharedMethod(object request)
{
//...
}
}
public class MyServices1 : MyServiceBase { ... }
public class MyServices2 : MyServiceBase { ... }
Shared logic using Request Context using Extension method
If you prefer not to use a base class, this can be re-factored behind an extension method as well:
public static void MyServiceExtensions
{
public static object SharedMethod(this IServicBase service, object request)
{
var sharedDep = service.TryResolve<ISharedDep>();
return sharedDep.SharedMethodWithRequestCtx(request, service.Request);
}
}
Loose Coupling by executing a Request DTO
If the issue is about a loose-coupled way to call Services without a reference to the implementation itself you can execute the Request DTO with the ServiceController:
public class MyService : Service
{
public object Any(Request requestDto)
{
var altDto = new AltRequest { Id = requestDto.Id };
var response = HostContext.ServiceController.Execute(altDto, base.Request);
//...
}
}
Note: this API is available as base.ExecuteRequest(requestDto) in v4.0.32+.
Uploading Files to a HTTP Service In Memory
If the issue is instead how to execute a Service that handles file uploads, there's an example in the embedded version of HttpBenchmarks showing how to call a Service that processes HTTP File uploads with a custom Request Context that uses local FileSystem files instead:
using (var admin = Resolve<AdminServices>())
{
//...
var dir = new FileSystemVirtualPathProvider(this, Config.WebHostPhysicalPath);
var files = dir.GetAllMatchingFiles("*.txt")
.Concat(dir.GetAllMatchingFiles("*.zip"));
admin.Request = new BasicRequest
{
Files = files.Map(x => new HttpFile {
ContentLength = x.Length,
ContentType = MimeTypes.GetMimeType(x.Name),
FileName = x.Name,
InputStream = x.OpenRead(),
} as IHttpFile).ToArray()
};
if (admin.Request.Files.Length > 0)
{
admin.Post(new UploadTestResults
{
TestPlanId = 1,
TestRunId = testRun.Id,
CreateNewTestRuns = true,
});
}
}
I am creating an application that consumes a SOAP web service in C#. I generated a proxy class for the web service WSDL using the svcutil tool.
I added the proxy class to my code and I am using it to make calls to the web service and get results asynchrounsly.
Everything works pretty fine when the client has an Internet access. However, if I run attempt to access while the application doesn't have Internet access it crashes raising the following exception:
An exception of type 'System.ServiceModel.EndpointNotFoundException' occurred in
System.ServiceModel.Internals.dll but was not handled in user code
I am trying to catch this exception to prevent the application from crashing and provide the user with a more friendly error message, However, since I am doing async web calls, simply surrounding the web service calls by a try- catch does not help.
According to the exception details it happens in the End_FunctionName function that is defined inside the auto-generated proxy file.
Any tips about how to be able to gracefully handle this exception ?
Its pretty difficult to know exactly what is happening; however, I'm going to assume you have a web service like such
[ServiceContract]
public interface IMyService
{
[OperationContract]
String Hello(String Name);
[OperationContract]
Person GetPerson();
}
You probably have a proxy like this :
public class MyPipeClient : IMyService, IDisposable
{
ChannelFactory<IMyService> myServiceFactory;
public MyPipeClient()
{
//This is likely where your culprit will be.
myServiceFactory = new ChannelFactory<IMyService>(new NetNamedPipeBinding(), new EndpointAddress(Constants.myPipeService + #"/" + Constants.myPipeServiceName));
}
public String Hello(String Name)
{
//But this is where you will get the exception
return myServiceFactory.CreateChannel().Hello(Name);
}
public Person GetPerson()
{
return myServiceFactory.CreateChannel().GetPerson();
}
public void Dispose()
{
((IDisposable)myServiceFactory).Dispose();
}
}
If you have an error connecting you will get it not when you try to connect to the channel factory but when you actually try to call a function.
To fix this problem, you can put a try catch around every single function call and handle async calls manually.
Conversely, you can have a function like init() that is called synchronously every single time you instantiate a connection. This way you know that if that call connects that you have a connection.
If you are at risk of a connection dropping at any time I advise you go with the former option.
Anyway here is an example of how you'd fix it:
public class MyPipeClient : IMyService, IDisposable
{
ChannelFactory<IMyService> myServiceFactory;
public MyPipeClient()
{
myServiceFactory = new ChannelFactory<IMyService>(new NetNamedPipeBinding(), new EndpointAddress(Constants.myPipeService + #"/" + Constants.myPipeServiceName + 2) );
}
public String Hello(String Name)
{
try
{
return Channel.Hello(Name);
}
catch
{
return String.Empty;
}
}
public Person GetPerson()
{
try
{
return Channel.GetPerson();
}
catch
{
return null;
}
}
public Task<Person> GetPersonAsync()
{
return new Task<Person>(()=> GetPerson());
}
public Task<String> HelloAsync(String Name)
{
return new Task<String>(()=> Hello(Name));
}
public void Dispose()
{
myServiceFactory.Close();
}
public IMyService Channel
{
get
{
return myServiceFactory.CreateChannel();
}
}
}
I uploaded the source I wrote so that you could download the full source. You can get it here : https://github.com/Aelphaeis/MyWcfPipeExample
PS : This Repository throws the exception you are getting. In order to remove it just go to MyPipeClient and remove the + 2 in the constructor.
If you are using a Duplex, Consider using this repository:
https://github.com/Aelphaeis/MyWcfDuplexPipeExample
I sure I'm missing something simple and obvious here but I can't find the answer:
I have a WCF service that returns Widgets. Widgets are defined in the service.
In my client program I also define and use Widgets. The Widget definition in the client and the service are identical. The problem is that Widgets returned by the service are ServiceReference1.Widget but the client program expects MyProgram.Widget. How do I get the client program to work with the service Widgets?
On the service:
[DataContract]
public class Widget
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public decimal Price { get; set; }
}
public class Service1
{
public async Task<IEnumerable<Widget>> GetAllWidgets()
{
await Task.Delay(Util.GetDelay(), CancellationToken.None);
return GetAllWidgets();
}
}
In the client program I also define Widgets. I call the service to get some:
public async Task<List<Widget>> GetWidgetsAsync() // expects MyProgram.Widget
{
using (ServiceReference1.Service1Client client =
new ServiceReference1.Service1Client())
{
var response = await client.GetAllProductsAsync();
return response; // gets ServiceReference1.Widget
}
}
Do I need to iterate through the response and build a duplicate set of client Widgets? Or do I define Widgets in a separate library and reference it from both client and server?
Thanks
The best way is to put the passed type (DTOs) and Service Interfaces into a shared library and reference it in both projects.
I'm also guessing you are autogenerating the client based on the service layer. Don't do this for the shared DLL scenario. See this article:
http://blog.walteralmeida.com/2010/08/wcf-tips-and-tricks-share-types-between-server-and-client.html