How to Roll back web service call - c#

Suppose I call a webservice to save some data to their local DB. After I get response from the webservice I check the response for following situation:
1- If failed to insert, I can easily roll back my entire code block using TransactionScope (In C#).
2- If it was successful I try to save these state (successful state) to my database. But before save the state my database server crashed! So I need to roll back web service call!
The code sample is like these:
//Calling database
var response = client.InsertNewItem(data);
if(response.IsSuccess)
{
myDb.SaveSucessfulState();
//Commit transaction
scope.compelte();
}
else
{
//Do roll back stuff.
}

You can look into WCF and transactions
http://msdn.microsoft.com/en-us/library/ff384250.aspx

Related

How Can Get Session With SessionId?

I use ASP.NET MVC. I have a problem. I set my variables to the session and I request a web service that doesn't belong to me. Then the web service makes an HttpPost request to my server.
It doesn't send a cookie to my server so I lost my session.
I think I can save my sessionid to the DB and I can get back my session with this ID. But I can't get any solution.
What's your suggestion?
public ActionResult SomeAction(){
mySettingService.saveSessionIdToDb(someToken, Session.SessionID);
var myPaymentFormObj = FormInit.Create(request, options);
myPaymentFormObj.DoRequest(); //it's callback to my another action with a token
}
[HttpPost]
public ActionView MyCallBack(string someToken){
//here is our app generates new session id and i lost my session because other server doesn't send me session id.
//i need to read session id from db and i can get my session maybe.
var mySessionId = mySettingService.getSessionIdFromDb(someToken);
//how can i start session like this?
Session.SessionID = mySessionId;
}
It seems like the problem you described is about maintaining the distributed transaction.
To describe it better your app is a service A and the webServer is service B.
You can perform an action which saves some changes to the database A including the session stuff then you send a call to service B which also can saves some changes to its DB or perform a bunch of other actions but in this case you don't care how it works, you only care about what kind of responses you get back with a callback. There should be an option to be able to send some kind of unique thing like userEmail or a transactionId which you can get back in a callback method to be able to recognize the transaction.
What I would suggest you do is something like
[HttpPost]
public ActionResult SendBlah(BlahData data){
var transactionId = Guid.NetGuid();
_sessionService.Create(transactionId, dataYouWantToStore)
_webServiceB.SendBlah(transactionId, data, token);
//optionally return info about call status / do other stuff
}
//or this can be of type HttpGet
[HttpPost]
public ActionView MyCallBack(string someToken, string tranactionId){
var sessionData = _sessionService.Get(tranactionId)
//do other stuff
}
If it's needed and you are using e.g. JWT you can store the transactionId/emailAddress/etc. there instead and read it.
Btw. it's always safer to store the session in the database instead of using some cache objects or relaying on cookies or javascript objects etc.
Also, it's better to be careful with the amount of data you want to store in a Session table in your db. I'd personally focus on storing the Ids and stuff like Status of given item etc.

How to manage distant database with C# and PHP

I don't know how to process, and when i search in the internet, there is so many solutions, I'm a bit lost.
My task is to create a leaderboard, the game is developed in C# with unity and my internship supervisor just told me "You have to put some PHP into the database server of our client and then make a "bridge" between our game and this PHP"
I never used C# before (Java is sooo cooler) any advice, source with commented code "easy" to understand?
You may want to write your API. You will then call it with C# using web requests.
A very simple way to get data from your database is to switch through given endpoints in your the URL.
For instance, the following URL: http://yourserver.com/api/v1/?leaderboard/top
You may explode the URL to get the endpoints with $endpoints = explode('/', rtrim($_SERVER['QUERY_STRING'], '/'));. In this case, $endpoints[0] would give leaderboard.
You could then use a switch statement to handle your request.
// ...
$endpoints = explode('/', rtrim($_SERVER['QUERY_STRING'], '/'));
switch ($endpoints[0])
{
case 'leaderboard':
{
switch ($endpoints[1])
{
case 'top':
// Ask your database
$result = get_top_leaderboard();
echo json_encode($result);
break;
// case ...
}
break;
// case...
}
}
// ...
Use the same method with $_POST to get user entries, and write them in your database. Do not forget to protect yourself from SQL injections.
In C#, perform a GET request on your API:
var responseString = await client.GetStringAsync("http://yourserver.com/api/v1/?leaderboard/top");
Keep in mind this exemple is not secured. If you want to get sensible data from your database, do not let your API unsecured with public access.

Prevent SELECT on a database during a transaction

I am building a Web API on which I apply some custom security mechanisms. In order to check if an operation is authorized I need to save its changes in the database within a transaction and do a commit or a rollback after.
Here is a simplified version of what I am doing:
public IHttpActionResult Post(Account account)
{
using (DbContextTransaction transaction = Context.Database.BeginTransaction())
{
Context.accounts.Add(account);
Context.SaveChanges();
// This will do one or several SELECTs on the database to do the verification
RollbackIfForbidden(transaction, account);
transaction.Commit();
}
return Ok();
}
What I need is to set an IsolationLevel on my transaction that locks the table (or the database) until the transaction is committed or rollbacked. This lock should delay any query done on the database while it is locked except for those that are sent by the method RollbackIfForbidden.
This would allow to prevent people to get erroneous data if they query the database between Context.SaveChanges(); and transaction.Commit(); but still accept any query done inside RollbackIfForbidden(transaction, account);.
Edit:
User story
The user sends a POST query to create an Account entity.
The service begins a transaction and store the account in the database.
The database can apply some modifications on the entity (via triggers or constraints).
The service query the new account with the changes made by the database.
The service checks that the current user has the right to create this specific account (based on the value that the user filled and that the database completed)
The service do a commit if the user is permitted, or do a rollback if he is forbidden.
The service returns the status of the operation (success or error).
My problem is that between the steps 2 and 6, another user may do a query on the database and get the created account while it may be removed in the step 6.
So I need to lock the database in the meantime but I also need to query the database in step 4 to get the new values of my entity.
You can use sp_getapplock to set your locking for transaction in sql server
https://msdn.microsoft.com/en-us/library/ms189823.aspx

Calling method async from WCF service and return immediately

A third party is calling our WCF service. The caller wants confirmation, that the sent records have been received and stored, within a small timeframe.
The records that are stored need some lenghty processing. Can the processing be executed async, right after storing the records, so the confirmation can be send immediately?
Ofcourse there can be a separate process that does the processing, but the question is whether I can combine storage and processing without timing out.
Update:
It looks like this works:
var aTask = new Task(myService.TheMethod);
aTask.Start();
return aVariableAsync;
Or is this a very bad idea to do from within my WCF host, because.. ?
You can set "AsyncPattern" to true on the OperationContract attribute as described on MSDN.
You can then control the concurrency using the following attribute on the service method:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
Yes it can be done. I dont have a ton of experience with it, but this is a snippet of some code showing that. The service calls this method on the controller that saves an xml message to the hard drive and then kicks off a separate task to process it into MongoDB and returns a message back to the service that it was successfully saved.
public string SaveTransaction(XElement pTransactionXml, string pSavePath)
{
//save the transaction to the drive locally
pTransactionXml.Save(pSavePath);
...
var mongoTask = Task.Run(async () =>
{
await SendXMLFilesToMongo(pSavePath);
});
return response.WithResult("Successfully saved to disk.");
}
public virtual async Task<int> SendXMLFilesToMongo(string pSavePath)
{
//call the code to save to mongo and do additional processing
}

C# webservices maintain session from another webservice

I have a webshop running which contains parts of cars. The prices next to the parts are loaded from a webservice running else where. This webservice only contains one webmethod: GetArticleInformation.
In this webservice there is a link to another webservice WebshopServiceClient running elsewhere which contains the info about the cars and holds the prices.
Now when a user select a part of the vehicle he wants to buy the first webservice is called and the method GetArticleInformation is executed. In this method I want to create a session which hold the logon of the second webservice ( the database ). In this way I want to prevent that for every call a new logon is required.
[WebMethod(EnableSession = true)]
public GetBackItems GetArticleInformation(User user, Items items)
{
//Create session if needed
client = (WebshopServiceClient)Session["SphinxLogon"];
if (client == null)
{
client = new WebshopServiceClient();
bool done = client.Logon();
if (done)
{
Session["SphinxLogon"] = client;
}
}
//Get information and send it back
...
}
Now when the user in the webshop selects a part the session is created but the next time the user selects a part the session is null again.
What am I doing wrong or what am I missing?
I would consider 'talking' to the various web-services via an internal 'proxy'-procedure -- fired up on app-start for example -- which would handle all traffic etc with the services. That way the individual client sessions do not have to logon or maintain a session with the services but can still be managed via the proxy. Individual clients would get a 'ticket' from the proxy which then could be part of their session and could be used to manage it.

Categories