I have 2 projects, project 1 have a reference to project 2.
Project 1 is using a simple service reference with a proxy class to connect to service. To be able to send username/password in header the following code is used on this proxy class :
public static void Connect()
{
_Myclient = new MyService.MyIntegrationClient();
_Scope = new OperationContextScope(_Myclient.InnerChannel);
IntegrationHeader ih = new IntegrationHeader
{
UserName = Properties.Settings.Default.MyUserLogin,
Password = Properties.Settings.Default.MyUserPassword
};
MessageHeader untyped = MessageHeader.CreateHeader("SecurityToken", "ns", ih);
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
}
So far so good, no problem to run and the usernamen/password can be read on service.
Project 2 are using channelFactory instead to connect to the same service. The code for creating the channel and adding messageheader looks like this :
public static IMyIntegration GetMyFactory(string userName, string password)
{
IMyIntegration client;
OperationContextScope operationContextScope;
IntegrationHeader integrationHeader;
ConfigurationChannelFactory<IMyIntegration> factory;
MessageHeader messageHeader;
integrationHeader = new IntegrationHeader { UserName = userName, Password = password };
messageHeader = MessageHeader.CreateHeader("SecurityToken", "ns", integrationHeader);
factory = new ConfigurationChannelFactory<IMyIntegration>("BasicHttpBinding_IMyIntegration", ConfigHelper.MyConfiguration, null);
client = factory.CreateChannel();
operationContextScope = new OperationContextScope((IClientChannel)client);
if (OperationContext.Current.OutgoingMessageHeaders.Count < 1)
OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
return client;
}
This is how the IntegrationHeader looks like :
[DataContract()]
public class IntegrationHeader
{
[DataMember]
public string UserName;
[DataMember]
public string Password;
}
Project 1 will first run a method in project 2 that connects(using above code) to a service Method at the service. After this is done project 1 will also make a connection to the same service but with the code that is first in this post.
So far so good, no problem.
Problem
The two service methods is then triggered again(a second time) but this time the above code is not needed because it was already done on the prev loop, so this time we do the service method request directly without creating any proxy classes or channelFactories.
The result is that the header on the sent message is missing this second time on the service?
If I remove the service call made by project 1 (the one with the proxy) there will be no problems?
Edit 1 :
If I only run the service calls that Project 1 does then it will work just fine, and if I only run the Service Calls that Project 2 does it will also work fine. The problem is when doing Project 2 call, Project 1 call and then back to Project 2 call again.
If I run it the other way around, Project 1, Project 2 then Project 1 again it will also fail on the same problem (third Project 1 call)?
Edit 2 :
I am using the OperationContext.Current.OutgoingMessageHeaders in both cases and it is only set the at the first call for each project, maybe thay are using the same context?
My guess is that the OperationContextScope is being disposed by the time your second call is made (after the one minute pause).
This will result in OperationContext.Current returning the previous instance of the operation context before the scope was created, which does not contain any headers.
The way to fix this would be to move the OpertationContextScope initialization out of the factory method:
var client = GetMyFactory("username", "password);
using (operationContextScope = new OperationContextScope((IClientChannel)client))
{
OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
client.DoSomething()
....
}
From MSDN:
When an OperationContextScope is created, the current OperationContext
is stored and the new OperationContext becomes the one returned by the
Current property. When the OperationContextScope is disposed, the
original OperationContext is restored.
Related
I'm currently working on a "server-app" / "client-app" project where the goal is to get some data from the server-app to the client app. I tried this with a WCF approach but since I've never worked with WCF it ain't an easy task for me.
So what I've already set up are the two apps in one solution à two different projects. Project one contains the server-app (TRunnerServer) and project two contains the client-app (TRunnerClient).
I've setup the interface for the service like that (in ServerApp MainWindowViewModel.cs):
[ServiceContract]
public interface ITRunnerService
{
[OperationContract]
ObservableCollection<Program> GetProgramList();
}
Than I've added the method to the class etc. like following:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
internal class MainWindowViewModel : ViewModelBase, ITRunnerService
{
public ObservableCollection<Program> GetProgramList()
{
return this.ProgramList;
}
public MainWindowViewModel()
{
var uris = new Uri[1];
string addr = "net.tcp://localhost:7000/MainWindowViewModel";
uris[0] = new Uri(addr);
ITRunnerService tRunnerService = this;
ServiceHost host = new ServiceHost(tRunnerService, uris);
var binding = new NetTcpBinding(SecurityMode.None);
host.AddServiceEndpoint(typeof(ITRunnerService), binding, string.Empty);
host.Open();
}
}
Now in the GUI of the application TRunnerClient I've got an button that I press to get the data from the TRunnerServer App.
I've just got an method binded with following:
private void Refresh(object parameter)
{
var uri = "net.tcp://localhost:7000/MainWindowViewModel";
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
var channel = new ChannelFactory<ITRunnerService>(binding);
var endPoint = new EndpointAddress(uri);
var proxy = channel.CreateChannel(endPoint);
this.ProgramList = proxy.GetProgramList();
}
Yet when I start the app only the client starts normal and the server app gives an exception based on the error warning from the xaml "A registration already exists for URI 'net.tcp://localhost:7000/MainWindowViewModel'".
How could I solve this problem?
Note: Other questions with a similar title didn't really helped me out before someone strikes it as duplicate.
The error message indicates that there is an old server process still hanging around. Try to kill it in the task manager and try again.
In order to avoid hanging processes, make sure that you exit the application gracefully and that you don't create any windows that you don't show and close.
the .net Windows Form application we developed (vb.net but c# answer is ok too) has some APIs (edit: yes, our own) to allow users to automate some tasks.
Everything is fine when the application is started through APIs by, say, Visual Studio. What we cannot get to work though is to assign an already running instance of our application to a new application object in visual studio.
We have seen there are some methods available for COM objects (getojbect) to access a running instance of an application but how about .net applications?
Rephrasing the question, we would like that, when a user calls the New() constructor of our application, the new object points to the running instance of our application (if any) instead of trying to create a new one (which is not possible by the way because we have made it single instance by checking through Mutex that no other instance of our application is running).
EDIT:
Sample code in the user application to automate some tasks
Imports TheApplication
Public Class WinFormByUser
Private ApplicationObject As TheApplication.MainForm
Public Sub OpenTheApplication()
ApplicationObject = New TheApplication.MainForm
Rem here theapplication should create a new instance if no instance of TheApplication is running. BUT, if an instance of the application
Rem is already running (in a different process, maybe started directly from the user), the ApplicationObject should point to the running
Rem instance from now on, instead of trying to create a new instance
ApplicationObject.DoSomething()
End Sub
End Class
Sample code inside TheApplication
Imports System.Threading
Public Class MainForm
Private ApplicationOpenedThroughAPI As Boolean = False
Private Shared mtx As Mutex
Private firstInstance As Boolean = False
Dim AppName As String = "TheApplicationName"
Public Sub New()
If Application.ProductName.ToString() <> AppName Then
Rem if TheApplication is opened externally through API the name is different therefore we can determine the boolean value
ApplicationOpenedThroughAPI = True
End If
mtx = New Mutex(True, AppName, firstInstance)
If firstInstance Then
InitializeComponent()
DoAllTheNecessaryStuff()
Else
If ApplicationOpenedThroughAPI = False Then
MsgBox("Application is running, can't open second instance")
Else
ReturnTheRunningInstance()
End If
End If
End Sub
Private Sub ReturnTheRunningInstance()
Rem please help here. what to do?
End Sub
Public Sub DoSomething()
Rem this does something and can be called by API user
End Sub
End Class
Please note that the solution could either be adding some code inside the application in the Sub ReturnTheRunningInstance() or in the user code, maybe checking if the application is running through something like Process.GetProcessesByName("TheApplicationName").Length and then do something in case.
Thanks!
We have seen there are some methods available for COM objects
(getojbect) to access a running instance of an application but how
about .net applications?
Let's start with this part. You essentially need to have one process access another process. .Net provides a variety of forms of cross-process communication. WCF seems the most appropriate here.
WCF is a large subject, but here's a basic architecture that might accomplish your goals.
Step 1
Have your application host a service, available to local callers over TCP.
Consider this pseudocode; there is plenty of documentation available on WCF once you know what to search for.
// the contract
[ServiceContract]
public interface IMyService
{
[OperationContract]
int Foo( int bar );
}
// the implementation
public MyService : IMyService
{
public int Foo( int bar ){ return bar * 100; }
}
// hosting the service within your application
var baseUri = new Uri( "net.tcp://localhost:59999/" );
var serviceHost = new ServiceHost( typeof( MyService ), baseUri );
// many options can/should be set here, e.g. throttling, security, and serialization behavior
var binding = new NetTcpBinding();
var endpoint = serviceHost.AddServiceEndpoint( typeof( IMyService ), binding, baseUri );
This is all you need for a caller to interface with an existing instance of the application, but it doesn't address the need to ensure that the app is running.
Step 2
A wrapper class may make it easier to locate/launch your application.
public sealed class MyWrapper
{
public IMyService GetService()
{
// TODO: perform appropriate OS-wide locking here
// TODO: see if app is running
// TODO: if not, launch it in a new process
// create a channel to connect the WCF endpoint we just defined
var channel = GetChannel();
// TODO: release lock
// return the channel to the caller
return channel;
}
public GetChannel( Binding binding, EndpointAddress endpointAddress )
{
var channelFactory = new ChannelFactory<IMyService>( binding, endpointAddress );
return _channelFactory.CreateChannel();
}
}
Step 3
Your callers can connect to your application from anywhere on the machine (or beyond, if you wish):
var wrapper = new Wrapper();
var service = wrapper.GetService();
int result = service.Foo( 123 );
While a bit unusual, your service code could also manipulate the GUI. For example:
var wrapper = new Wrapper();
var service = wrapper.GetService();
// call a method, the implementation of which launches a "contact form"
// with data preloaded for the specified contact ID
service.ShowContactForm( 1 );
Cleanup
Note that this syntax I've shown so far is elegant, but it doesn't handle closing the channel or channel factory. There are a variety of ways to do this; I've used a pattern like this:
public sealed class ServiceClient
{
private readonly ChannelFactory<IMyService> _channelFactory;
public ServiceClient( Binding binding, EndpointAddress endpointAddress )
{
_channelFactory = new ChannelFactory<IMyService>( binding, endpointAddress );
Channel = _channelFactory.CreateChannel();
}
public IMyService Channel { get; private set; }
public void Dispose()
{
if( Channel != null )
{
// TODO: check the state of the channel and close/abort appropriately
}
if( _channelFactory != null )
{
_channelFactory.Close();
}
}
}
public sealed class MyWrapper
{
public ServiceClient GetClient()
{
// Similar setup to the previous example, except the service client wraps
// the channel factory.
}
}
var wrapper = new Wrapper();
using( var client = wrapper.GetClient() )
{
client.Channel.Foo( 123 );
}
It's a bit more verbose, but it gives you much more control over cleanup and any other options you wish to control.
Solution Structure
All of this code can potentially live in one assembly. However, it may be cleaner to place the wrapper in a separate assembly and the service contract(s) interfaces into another assembly referenced by the wrapper and the main application.
Assembly 1: service contracts (interfaces)
Assembly 2: GUI application, references assembly 1 and implements its service contracts
Assembly 3: wrapper class, references assembly 1
OK we are using message security with username credentials (and X509 certificate encryption) to communicate with our WCF service. I am not happy with this approach but that is not the point of question and I do not want to get into that.
I am using Windsor Castle to generate proxies in ASP NET Web Forms + MVC hybrid. We are using forms authentication and use user's credentials to communicate with WCF services - this will help auditing all calls. As I said, I am not happy with this approach but that is not the point.
I have created CustomCredentials class which inherits AbstractCredentials class and WcfFacility happily uses it to configure my proxies. As you will see below, all my setup is just a few lines. I have created unit test below which demonstrates all I am doing: creating a proxy, making a call and then releasing it in a loop. Now I am expecting this test to work but it does not and I get
Expected: 10 But was: 1
I have not included binding but that is irrelevant, as I said I am using Message Security with X509 certificates.
I know that for channel factory with message security, once opened you cannot change credentials. Is this the same issue?
Is this a bug in WcfFacility or a limitation?
Here is the code
[TestFixture]
public class Harness
{
private IWindsorContainer _container;
public static int NumberOfTimesCredentialsConfigured = 0;
[SetUp]
public void Setup()
{
_container = new WindsorContainer().AddFacility<WcfFacility>();
Component
.For<IFrameworkUsers>()
.ActAs(DefaultClientModel
.On(WcfEndpoint.FromConfiguration("FrameworkUsersService"))
.Credentials(new CustomCredentials()))
.LifeStyle.Transient);
}
[Test]
public void MultipleProxyTest()
{
const int Runs = 10;
NumberOfTimesCredentialsConfigured = 0;
for (int i = 0; i < Runs; i++)
{
IFrameworkUsers frameworkUsers = _container.Resolve<IFrameworkUsers>();
frameworkUsers.CreateUserSession();
_container.Release(frameworkUsers);
}
Assert.AreEqual(Runs, NumberOfTimesCredentialsConfigured);
// FAILS!!! Expected: 10 But was: 1
}
[TearDown]
public void TearDown()
{
}
}
public class CustomCredentials : AbstractCredentials
{
#region Overrides of AbstractCredentials
protected override void ConfigureCredentials(ClientCredentials credentials)
{
credentials.UserName.UserName = "testuser";
credentials.UserName.Password = "abcdef";
Harness.NumberOfTimesCredentialsConfigured++;
}
#endregion
}
I posted on castle forum and no reply. It is a problem by design in WCF Facility in which they cache service channels which is OK with no security but does not work with security.
Your credentials and IWcfEndpoint in general (which is the result of DefaultClientModel.On(...) call) are created only once when the container is configured. If you want to provide different credentials each time - you need to make them dynamic dependency like below:
_container.Register(Component.For<IFrameworkUsers>()
.AsWcfClient()
.DependsOn(
(k, d) => d["endpoint"] =
new DefaultClientModel(WcfEndpoint.FromConfiguration("FrameworkUsersService"))
.Credentials(new CustomCredentials())
)
.LifeStyle.Transient);
String endpoint here is the name of dependency consumed by WcfFacility. I'm not sure where exactly, but it is resolved in some interceptor (you may set breakpoint in the lambda and debug your test to look at call stack). I assume it is made to match name of AsWcfClient(IWcfEndpoint endpoint) method argument.
So the answer is no, it is nor bug nor limitation of WcfFacility.
I am writing a remote service for an application using WCF, in which login information is kept in a database. The service requires session establishment through a login or account creation call. There is no ASP involved.
Now, when a client starts a session by calling an exposed IsInitiating method, I check the account data provided against the information on the database and, if it is not correct, I want to invalidate that session and force the client to start again with a call to an IsInitiating method.
Looking at some other questions, I have found pros and cons for two ways to invalidate a session. One does so the hard way, by throwing a FaultException; the other with softer manners, storing accepted session IDs.
Now, the first one, although achieving what I desire, is way too aggressive, given that incorrect logins are part of the normal flow of the application. The second one, on the other hand, allows the client to continue calling non-initiating methods, eventhough they will be rejected, while also incurring in a considerable code overhead on the service due to the added thread safety requirements.
So, the question: Is there a third path which allows the service to invalidate the session initialization and communicate it to the client, so it is forced to make a new IsInitiating call?
A reduced version of the code I have:
[DataContractAttribute]
public class AccountLoginFault
{
public AccountLoginFault (string message)
{
this.Message = message;
}
[DataMemberAttribute]
public string Message { get; set; }
}
[ServiceContract (SessionMode = SessionMode.Required)]
public interface IAccountService
{
[OperationContract (
IsInitiating = true)]
[FaultContractAttribute (
typeof (AccountLoginFault),
ProtectionLevel = ProtectionLevel.EncryptAndSign)]
bool Login (AccountData account, out string message);
}
[ServiceBehavior (
ConcurrencyMode = ConcurrencyMode.Single,
InstanceContextMode = InstanceContextMode.PerSession)]
public class AccountService : IAccountService
{
public bool Login (AccountData account, out string message)
{
UserManager userdb = ChessServerDB.UserManager;
bool result = false;
message = String.Empty;
UserData userData = userdb.GetUserData (account.Name);
if (userData.Name.Equals (account.Name)
&& userData.Password.Equals (account.Password))
{
// Option one
// Get lock
// this.AcceptedSessions.Add (session.ID);
// Release lock
result = true;
} else
{
result = false;
// Option two
// Do something with session context to mark it as not properly initialized.
// message = "Incorrect account name or password. Account provided was " + account.Name;
// Option three
throw new FaultException<AccountLoginFault> (
new AccountLoginFault (
"Incorrect account name or password. Account provided was " + account.Name));
}
return result;
}
}
Throwing an exception is by far the easiest option because WCF enforces that the session cannot be re-used. From what I gather, what you would like the third party component to accomplish comes quite close to this functionality. But, instead of forcing the client to call IsInitialized again, you would force the client to create a new connection. This looks like a very small difference to me.
An alternative would be to have a private variable bool _authorised and check this variable at every method call.
Do something like this:
public ConnectResponseDTO Connect(ConnectRequestDTO request) {
...
if(LoginFailed)
OperationContext.Current.OperationCompleted += FaultSession;
}
private void FaultSession(object sender, EventArgs e) {
var context = (OperationContext) sender;
context.Channel.Abort();
}
This will fault the channel and the client will havce to reesatablish the session.
hi i have to use a web service in my solution
I have a wrapper static class accessing web service as
public static class Authentication
{
public static bool VerifyPassword(int membershipID, string password)
{
PCIValidationResult result = CreatePciWebService().ValidatePassword(
membershipID, password);
LoginValidationResult loginValidationResult =
(LoginValidationResult)Enum.ToObject(
typeof(LoginValidationResult), result.ResultCode);
return true;
}
private static PCIWebService CreatePciWebService()
{
PCIWebService service = new PCIWebService();
service.Url = KioskManagerConfiguration.PciServiceUrl;
return service;
}
and I call this class in code
like
Authentication.VerifyPassword(23,"testUser");
First call of code is succeed And after 2nd call the code
I got " the operation has timed out" after 2-3 min. waiting ...
How to call a web service ?
Apart from always returning true, and possibly using using (if the service is IDisposable), I can't see anything obviously wrong.
Have you tried tracing it with fiddler or wireshark to see what is happening at the transport level?
You could try adding using, but while this may tidy things up I'm not sure it will fix this issue:
using(PCIWebService svc = CreatePciWebService()) {
PCIValidationResult result = svc.ValidatePassword(membershipID, password);
//...etc
}