I want to create a C# application that communicates with two SOAP webservices. These webservices (WSDL files) use the same url
<root>/...dirPath.../dms.cfc?wsdl
<root>/...dirPath.../cobra.cfc?wsdl
<root> should be dynamic because the application user has to set this variable.
First of all I took this
How can I dynamically switch web service addresses in .NET without a recompile?
and tried this
https://www.codeproject.com/Articles/12317/How-to-make-your-Web-Reference-proxy-URL-dynamic
Further I found this link
https://learn.microsoft.com/en-us/sql/reporting-services/report-server-web-service/net-framework/setting-the-url-property-of-the-web-service?view=sql-server-2017
but these links didn't help I can't find the settings URL behaviour and I can't access the URL property by code.
I created a static class that should handle both webservices. The user is able to change the webservice root url.
An example URL would be
http://localhost:8500/CoBRA/...dirPath.../dms.cfc?wsdl
or
http://myInstance.com/CoBRA/...dirPath.../dms.cfc?wsdl
handled by this code
public static class CoBRAService
{
private static cobraClient cobraBaseClient = new cobraClient();
private static dmsClient cobraDmsClient = new dmsClient();
public static void SetWebserviceRootUrl(string rootUrl)
{
// cobraBaseClient.url = $"{rootUrl}/path/dms.cfc?wsdl";
// cobraDmsClient.url = $"{rootUrl}/path/cobra.cfc?wsdl";
}
}
Both webservices don't inherit from System.Web.Services.Protocols.SoapHttpClientProtocol they implement this public partial class cobraClient : System.ServiceModel.ClientBase<MyProject.CoBRA_Base.cobra>, MyProject.CoBRA_Base.cobra
This is my project structure
Where can I set the webservice url or how can I access the url property?
if your "CoBRA_BaseClient" and "CoBRA_DMSClient" inherited from System.ServiceModel.ClientBase< TChannel >
then you can try the following:
public static CoBRA_BaseClient CreateService()
{
CoBRA_BaseClient service = new CoBRA_BaseClient();
service.Endpoint.Address = new EndpointAddress("uri");
return service;
}
public static CoBRA_DMSClient CreateService()
{
CoBRA_DMSClient service = new CoBRA_DMSClient();
service.Endpoint.Address = new EndpointAddress("uri");
return service;
}
Related
I created WCF service and calling it from the android studio and its working fine, but after implementing WCF perSession functionality it is working for a single user at a time.
Problem:
My problem is when i am hitting WCF url with multiple user my sessionID get overwrite by the latest logged in user, So how to maintain session for multiple user like we do in web application.
I used this to creste session in WCF:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
and this is my method to create sessionid within services class
public class MyService : IMyService
{
static string currentSessionID = string.Empty;
public string createSession()
{
currentSessionID = DateTime.Now.Ticks.ToString();
return currentSessionID;
}
public string Login()
{
var mysessionId = createSession();
return mysessionId;
}
public string Mymethods(string data)
{
string response = "";
if(data.StartsWith("01"))
response = Login();
return response;
}
}
and am hitting this createSession() method only in login function.
Please help me out of this.....
Thanks in advnance.
In c# .Net Framework 4.5 (Visual Studio Ultimate 2012, Version 11.0.61219.00 Update 5), I'm trying to define a service variable at runtime for which webservice to use. Each webservice (there are many) are all defined the same except for the endpoint url but the credentials will not cross over to authenticate. The below condition is menial to simplify the issue at hand. The following code gives the error: Cannot implicitly convert type WebService2.Service to WebService1.Service.
What I've tried: calling functions to return the proper service but the parameters or assignment all require a specific type.
var service = new WebService1.Service();
service = new WebService2.Service();
I want to be able to use the variable service in the rest of the program without having to duplicate code everywhere for using the many web service references.
It seems like what you are looking to do, you would need a common interface between the two services so you could inject whichever service you wish to use.
public class WebService1 : IWebService {...service code}
public class WebService2 : IWebService{...service code}
public interface IWebService{...service methods you will be calling}
Then you could do the following.
IWebService service = new WebService1.Service();
service = new WebService2.Service();
Assuming that the different services share the same method names, you can create an interface that all of the services implement by using the interface
IMyService.cs
interface IMyService
{
void MyMethod(string filter);
}
MyWebServiceImplementation.cs
public class MyWebServiceImplementation : IMyService
{
public void MyMethod(string filter);
}
MySecondWebServiceImplementation.cs
public class MySecondWebServiceImplementation : IMyService
{
public void MyMethod(string filter);
}
MyImplemetationCode.cs
//Use different services from same variable
IMyService service = new MyWebServiceImplementation();
service.MyMethod("filter");
service = new MySecondWebServiceImplementation();
service.MyMethod("another filter");
I am a new C# developer and I am trying to re-use the API client that I built based on the Ultimate RestSharp Client in ASP.NET and C# explained in this post. I was able to create all the classes and prerequisites mentioned in the article, but I am unable to use the client class right now over some places in my application
Here's the client code:
public class UsersClient : BaseClient
{
public UsersClient (ICacheService cache, IDeserializer serializer, IErrorLogger errorLogger)
: base(cache, serializer, errorLogger, "http://yourBaseUrl.com") { }
public User GetByID(int id)
{
RestRequest request = new RestRequest("users/{id}", Method.GET);
request.AddUrlSegment("id", id.ToString());
return GetFromCache<User>(request, "User" + id.ToString());
}
}
Now, when I am trying to call the GetById method in the code-behind of some ASP.NET pages, I could not see or access this method and I don't know why. Here's the line of code I am using to access the method:
string userId = "JohnA";
var user = UsersClient.GetById(userId);
So how can I access this method? or how can I use the API client over my application?
UPDATE:
I am still struggling with this API client. Could you please show me how I can use it and how I can apply dependency injection?
You cannot access non-static method like that. First you have to initialize UsersClient object.
ICacheService cache = //initialize cache here
IDeserializer deserializer = //initialize deserializer here
IErrorLogger errorLogger = //initialize errorLogger here
UsersClient usersClient = new UsersClient(cache, deserializer, errorLogger);
string userId = "JohnA";
var user = usersClient.GetById(userId);
I would recommend to learn about design patterns like dependency injection and inversion of control (already used, not sure if it was intended or unconsciously) and use them in this case.
If you're looking to access this method by static reference. You'll have to make the adjustments below. (Add the word static to the GetByID method).
public class UsersClient : BaseClient
{
public UsersClient (ICacheService cache, IDeserializer serializer, IErrorLogger errorLogger)
: base(cache, serializer, errorLogger, "http://yourBaseUrl.com") { }
public static User GetByID(int id)
{
RestRequest request = new RestRequest("users/{id}", Method.GET);
request.AddUrlSegment("id", id.ToString());
return GetFromCache<User>(request, "User" + id.ToString());
}
}
First of all, I want to share my scenario what i want to build -
Scenario:
I am building a client app using wpf. In some cases, I need to call a web service to get data from the server. In order to do this, I added a web reference using wsld url. And I created a ServiceManager class that will call service method. For security reason, I need to add some header info at soap xml request for example, UserToken, SAML Token and so on. I can this from my ServiceManager class. But I want to add another class which will be called before sending request to the server. In that class, I will do something like adding security header to soap xml request with request and then send it to the server.
I used SOAP Extension to fulfill my purpose and it works well. But the problem is, every-time I need to add annotation in Reference.cs (for each web service reference) file at top of the service method. I believe that there is some other easiest way to make this working better than SOAP Extension. Is there any way where I can only call the service and a delegate class will be called automatically and I don't need to add any annotation to the reference file? I will share my sample code here.
ServiceManage class:
public class ServiceManager
{
public UserDataService dataService; //web service added at Web Reference
public ServiceManager()
{
dataService = new UserDataService();
getUserServiceRequest rqst = new getUserServiceRequest();
getUserServiceResponse resp = dataService.getUser(rqst);
}
}
Reference.cs
[TraceExtensionAttribute(Name = "First")]
public getUserServiceResponse getUser([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] getUserServiceRequest request) {
object[] results = this.Invoke("getUser", new object[] {
request});
return ((getUserServiceResponse)(results[0]));
}
TraceExtensionAttribute.cs
[AttributeUsage(AttributeTargets.Method)]
public class TraceExtensionAttribute : SoapExtensionAttribute
{
private string mstrName = null;
public override Type ExtensionType
{
get { return typeof(TraceExtension); }
}
public override int Priority
{
get { return 1; }
set { }
}
public string Name
{
get { return mstrName; }
set { mstrName = value; }
}
}
TraceExtension.cs
public class TraceExtension : SoapExtension
{
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attr){//..do something}
public override void Initialize(object initializer){//..do something}
public override Stream ChainStream(Stream stream){//...do something}
public override void ProcessMessage(SoapMessage message) {//..do something}
}
Finally, I found the solution. Just through out Web Reference and add Service Reference instead. Then go to the following link. It works for me.
First of, let me start by saying I have no experience of doing endpoint/networking type of stuff, so my question might seem a bit stupid, so please bear with me :)
I am working on porting an App written for Windows Phone 7 onto Windows 8 (Metro app). In the original App, there was a ServicesReference.ClientConfig file which defined the URL, bindings and other bits for the App to connect to the server (addresses changed):
<client>
<endpoint address="https://someurl.com/userservice.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_UserServices"
contract="UserApi.UserServices" name="User_Services" />
<endpoint address="https://someurel.com/dataservice.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_DataServices"
contract="DataApi.DataServices" name="Data_Services" />
Also, in the WP7 project, there were already two "Service References" added (one for User Services and one for Data Services), with supporting Reference.cs generated files. When I tried adding the service references into the Win8 project (VS2012), it generated a blank reference.cs file, so I simply added the Reference.cs file from the WP7 project into the W8 project, and also copied the ServiceReferences.ClientConfig file into the W8 project (so in terms of directory structure, it looked identical to the WP7 project).
I think these Reference.cs files are the ones which provide the interface for the contracts
Now, when I run my W8 app, I get an error during the part where it needs access to the service:
InvalidOperationException was unhandled by user code
Could not find endpoint element with name
'User_Services' and contract
'UserApi.UserServices' in the ServiceModel client
configuration section. This might be because no configuration file was
found for your application, or because no endpoint element matching
this name could be found in the client element.
So I figured the App isn't using the ServicesReferces.ClientConfig file to pickup the endpoints and network adresses, or it wasn't finding the Reference.cs files which I have importes into the project. So, assuming first it is not finding the endpoints correctly through the ServicesReferences.ClientConfig file, is it possible to do the same in code?
All I got so far is this:
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress(new Uri("https://someurl.com/someservice.svc"));
but I don't how to take this further (I added this into App.xaml.cs)
Hope the question makes sense. If there is any further information you need, please let me know and I will try to find out about it while I go and educate myself more on this endpoint business
Thanks in advance
I had the same problem and I tried to wrap everything in some classes.. This is what I did:
First of all, I created a class called ClientService where it creates and wraps the EndpointAdress:
EDIT for Win8:
public class ClientService
{
public Type ContractType {get;set;}
public EndpointAdress EndpointAdress {get;set;}
public Binding Binding { get; private set; }
public ClientService(Type contractType)
{
ContractType = contractType;
CreateEndpoint();
CreateBinding();
}
private void CreateEndpoint()
{
EndpointAdress = new EndpointAddress(....) //You can get some parameters about the service adress in the Constructor of this class
}
private void CreateBinding()
{
Binding = new BasicHttpBinding(); //Or your specific Binding
}
}
Once I have this, I create a static class with all my client registrations. I add all of them once I start my app. Something like this:
ClientServices.AddClientService(new ClientService(typeof(IYourService));
public static class ClientServices
{
private static readonly Dictionary<Type, ClientService> _clientServices;
static ClientServices()
{
_clientServices = new Dictionary<Type, ClientService>();
}
public static void AddClientService(ClientService clientService)
{
if (!_clientServices.ContainsKey(clientService.ContractType))
{
_clientServices.Add(clientService.ContractType, clientService);
}
}
public static ClientService GetClientServiceBy(Type contract)
{
if (_clientServices.ContainsKey(contract))
{
return _clientServices[contract];
}
throw new ArgumentException(string.Format("The contract's Type {0} is not registered. Please register the client's endpoint.", contract));
}
}
So, when my application starts I have all my client endpoints registered in a static class. Now when I want to call a service I have a wrapper called ServiceInvoker. I use it like this whenever I want to call a Service:
var invoker = new ServiceInvoker();
var result = invoker.InvokeService<IMyService, MyObjectReturnType>(
proxy => proxy.DoSomething(myParameters));
return result;
Where InvokeService looks like this:
public TResult InvokeService<TServiceContract, TResult>(Func<TServiceContract, TResult> invokeHandler) where TServiceContract : class
{
ICommunicationObject communicationObject;
var arg = CreateCommunicationObject<TServiceContract>(out communicationObject);
var result = default(TResult);
try
{
result = invokeHandler(arg);
}
catch (Exception ex)
{
throw;
}
finally
{
try
{
if (communicationObject.State != CommunicationState.Faulted)
communicationObject.Close();
}
catch
{
communicationObject.Abort();
}
}
return result;
}
private TServiceContract CreateCommunicationObject<TServiceContract>(out ICommunicationObject communicationObject)
where TServiceContract : class
{
var clientService = GetClientService(typeof(TServiceContract));
var arg = new ChannelFactory<TServiceContract>(clientService.Binding, clientService.EndpointAdress).CreateChannel();
communicationObject = (ICommunicationObject)arg;
return arg;
}
private ClientService GetClientService(Type type)
{
var clientService = ClientServices.GetClientServiceBy(type);
return clientService;
}
The main problem here is that since DLL's cannot be referenced in a Windows Store App, the only way to make this example work is to copy all Service Interfaces and possible ojects that we transfer to a Class Library (Windows Store apps). This way we will be able to create a channel and connect to the WCF service.
Copying the interfaces can be a workaround but is NOT a good approach.
Service Reference or other code generation tools are the way to go.
In addition, async and await are not possible in this scenario.
**ServiceInvoker apprach is used from creating WCF ChannelFactory