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
}
Related
The Situation
I'm working on a OAuth2 Api Wrapper. Some api routes are for logged people and some for anonymous and logged.
Here is an example of one method in my wrapper :
public async Task<UploadListResponse> List(bool pagination = false, int page = 1, int limit = 10)
{
var request = UploadRequests.List(pagination, page, limit);
var cancellationTokenSource = new CancellationTokenSource();
var restResponse = await Context.Client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
return restResponse.Handle<UploadListResponse>();
}
I build a request with all parameter set up then execute the request and then handle the answer in case I have an api error and then output an object containing all the data that request gave me.
The problem
With OAuth2, when you log to the API you'll receive an access token and a refresh token. If your access token is expired you have to contact the api with your refresh token to get a fresh new access token.
As I said earlier some of my method needs you to be logged but if your access token is expired I want to try to refresh token before throwing an exception like with this method :
public async Task<bool> NeedRelog()
{
try
{
var validAuth = await ValidAuth();
}
catch
{
try
{
var refresh = await Refresh(Context.Client.Config.RefreshToken);
}
catch
{
return true;
}
}
return false;
}
ValidAuth check with the API if you are logged and if I have an exception then I'll try to refreshToken.
I want to tag method that need logged to call NeedRelog() and those who aren't tag to not call it.
I may just do it in every method but it wouldn't be clean.
What I've done so far
I've found a great tool : PostSharp that seems to fit my needs.
I've started to do a checkLog aspect like this :
[Serializable]
public class CheckLog : OnMethodBoundaryAspect, IOnStateMachineBoundaryAspect
{
public CheckLog()
{
ApplyToStateMachine = false;
}
public override void OnEntry(MethodExecutionArgs args)
{
var instance = (ApiService)args.Instance;
var res = instance.Parent.OAuth.NeedRelog().Result;
if (!res)
{
args.Exception = new Exception("Need to relog");
args.FlowBehavior = FlowBehavior.Return;
}
}
}
Where I'm stuck
The Main problem is with the call to my NeedRelog() Method. Due to the fact this is an async method I'm struggling to make my aspect await for it.
If my OnEntry method is async then It won't block the call if you are not logged.
If my OnEntry method is not async and I wait for needLog it freeze and nothing happen.
I really want to know to use this kind of "conditional method call" with postsharp, it looks awesome but the fact is after looking for hours in the documentation I didn't find a way to do what I want.
I'm starting to ask myself if it is even possible to achieve what I'm aiming to do.
Did you try using a way to make the call synchronous maybe with something like this stackoverflow.com/a/25097498/3131696 ? – M22an 5 hours ago
As I can't mark a comment as answering a question I quote your comment to make this question answered as it is said here : link
Thanks you for this M22an.
I'm currently using SignalR to communicate between a server and multiple separate processes spawned by the server itself.
Both Server & Client are coded in C#. I'm using SignalR 2.2.0.0
On the server side, I use OWIN to run the server.
I am also using LightInject as an IoC container.
Here is my code:
public class AgentManagementStartup
{
public void ConfigurationOwin(IAppBuilder app, IAgentManagerDataStore dataStore)
{
var serializer = new JsonSerializer
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
TypeNameHandling = TypeNameHandling.Auto,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
};
var container = new ServiceContainer();
container.RegisterInstance(dataStore);
container.RegisterInstance(serializer);
container.Register<EventHub>();
container.Register<ManagementHub>();
var config = container.EnableSignalR();
app.MapSignalR("", config);
}
}
On the client side, I register this way:
public async Task Connect()
{
try
{
m_hubConnection = new HubConnection(m_serverUrl, false);
m_hubConnection.Closed += OnConnectionClosed;
m_hubConnection.TraceLevel = TraceLevels.All;
m_hubConnection.TraceWriter = Console.Out;
var serializer = m_hubConnection.JsonSerializer;
serializer.TypeNameHandling = TypeNameHandling.Auto;
serializer.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
m_managementHubProxy = m_hubConnection.CreateHubProxy(AgentConstants.ManagementHub.Name);
m_managementHubProxy.On("closeRequested", CloseRequestedCallback);
await m_hubConnection.Start();
}
catch (Exception e)
{
m_logger.Error("Exception encountered in Connect method", e);
}
}
On the server side I send a close request the following way:
var managementHub = GlobalHost.ConnectionManager.GetHubContext<ManagementHub>();
managementHub.Clients.All.closeRequested();
I never receive any callback in CloseRequestedCallback. Neither on the Client side nor on the server side I get any errors in the logs.
What did I do wrong here ?
EDIT 09/10/15
After some research and modifications, I found out it was linked with the replacement of the IoC container. When I removed everything linked to LightInject and used SignalR as is, everything worked. I was surprised about this since LightInject documented their integration with SignalR.
After I found this, I realised that the GlobalHost.DependencyResolver was not the same as the one I was supplying to the HubConfiguration. Once I added
GlobalHost.DependencyResolver = config.Resolver;
before
app.MapSignalR("", config);
I am now receiving callbacks within CloseRequestedCallback. Unfortunately, I get the following error as soon as I call a method from the Client to the Server:
Microsoft.AspNet.SignalR.Client.Infrastructure.SlowCallbackException
Possible deadlock detected. A callback registered with "HubProxy.On"
or "Connection.Received" has been executing for at least 10 seconds.
I am not sure about the fix I found and what impact it could have on the system. Is it OK to replace the GlobalHost.DependencyResolver with my own without registering all of its default content ?
EDIT 2 09/10/15
According to this, changing the GlobalHost.DependencyResolver is the right thing to do. Still left with no explanation for the SlowCallbackException since I do nothing in all my callbacks (yet).
Issue 1: IoC Container + Dependency Injection
If you want to change the IoC for you HubConfiguration, you also need to change the one from the GlobalHost so that returns the same hub when requesting it ouside of context.
Issue 2: Unexpected SlowCallbackException
This exception was caused by the fact that I was using SignalR within a Console Application. The entry point of the app cannot be an async method so to be able to call my initial configuration asynchronously I did as follow:
private static int Main()
{
var t = InitAsync();
t.Wait();
return t.Result;
}
Unfortunately for me, this causes a lot of issues as described here & more in details here.
By starting my InitAsync as follow:
private static int Main()
{
Task.Factory.StartNew(async ()=> await InitAsync());
m_waitInitCompletedRequest.WaitOne(TimeSpan.FromSeconds(30));
return (int)EndpointErrorCode.Ended;
}
Everything now runs fine and I don't get any deadlocks.
For more details on the issues & answers, you may also refer to the edits in my question.
I'm trying to create a singleton object which should be in use for each call to my server.
But for some reason the static object is keep renew for each call to the Web API.
Is there any way to stop it? What can I do?
Thanks for the answers, Here is some code:
The Singleton:
private static CoreEngine _instance;
public static CoreEngine Instance
{
get { return _instance ?? (_instance = new CoreEngine()); }
}
private CoreEngine(){}
The WebAPI method:
CoreEngine _coreEngine = CoreEngine.Instance;
[System.Web.Http.Route("Compare")]
public void PostCompare([FromUri]string pluginName, [FromUri]string file)
{
var plugin = _coreEngine.GetPlugin(pluginName);
if (plugin == null)
return;
plugin.Compare(file);
And a simple client:
public void Post(string uri, Dictionary<string,string> postDic)
{
using (var client = new HttpClient())
{
var postUri = FromDictionaryToUriString(uri, postDic);
var response = client.PostAsync(postUri, null).Result;
}
}
Its only one thread and sync.
I tried to repeate the same POST method for two times and in the first time I had the first instance of the CoreEngine while in the secound call, The CoreEngine has been disposed and the instance were re-created.
The short answer is: That's how it's supposed to work. The long answer is already written here.
I tried to replicate this strange behavior and could not. My static variables remained that way across multiple requests. Static objects should be used with care on .NET Web Api as they stay in memory across requests until the App Pool gets recycled. They are also not thread-safe.
A better place exists such as
HttpContext.Current.Application["myKey"]
Also you can use separate processes similar to Redis.io to maintain a cache on that machine, or across machines.
See Synchronizing Data for Multithreading
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.
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.