Below is what the request looks like in the web app.
Request URL:http://myurl.com/rest
Request Method:PUT
Status Code:200 Ok
Request Headersview source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:60
Content-Type:application/json
Cookie:ui_dom_other=block; session=sessionkey; acct_table#pageNavPos=1; ui_usr_feat=block
Host:http://myurl
Origin:http://myurl.com
Referer:http://myurl.com/referer
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Request Payload view parsed
{"table":"users","settings":[{"name":"dnd","value":"true"}]}
Response Headersview source
Cache-Control:no-cache
Content-Length:2
Content-Type:application/json
The data is in the request payload field
{"table":"users","settings":[{"name":"dnd","value":"true"}]}
Below is my current C# RestSharp code
// Initiate Rest Client
var client = new RestClient("http://myurl.com");
var request = new RestRequest("resturl/restrequest");
// Set headers, method and cookies
request.Method = Method.PUT;
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Accept", "*/*");
request.AddCookie("session", sessionKey);
// Set Data format
request.RequestFormat = DataFormat.Json;
// Set Data
string theString = "{'table':'users','settings':[{'name':'dnd','value':'true'}]}";
request.AddBody(theString);
// Execute
var test123 = client.Execute(request);
I've been able to successfully do all my GET/POST calls however PUT has not been successful.
Fiddler Capture
Web App - Working
PUT http://myurl HTTP/1.1
Host: http://myurl
Connection: keep-alive
Content-Length: 60
Origin: hhttp://myurl
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Content-Type: application/json
Accept: */*
Referer: http://myurl
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cookie: ui_dom_other=block; session=sessionkey; acct_table#pageNavPos=1; ui_usr_feat=block
{"table":"users","settings":[{"name":"dnd","value":"true"}]}
C# Application - Not Working
PUT http://myurl HTTP/1.1
Accept: */*
User-Agent: RestSharp/105.0.1.0
Content-Type: text/xml
Host: http://myurl
Cookie: session=sessionkey
Content-Length: 10
Accept-Encoding: gzip, deflate
<String />
Instead of adding a string as the payload consider adding an object:
request.AddBody(new { table = "users", settings = new[] { new { name = "dnd", value = "true" } } });
Related
[Edit - Added analysis from fiddler, added more code to copy over authentication header]
[Edit - now use FormUrlEncodedContent]
I have a page here: https://www.cdc.co.nz/products/list.html?cat=5201 that is password protected via login over here: https://www.cdc.co.nz/login/
The code below allows me to login successfully. However, despite using the same client, I am unable to make a call to the page mentioned above (401 Unauthorized)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
var baseAddress = new Uri("https://www.cdc.co.nz");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer, UseCookies = true })
using (HttpClient client = new HttpClient(handler) { BaseAddress = baseAddress })
{
HttpResponseMessage response = null;
//Let's visit the homepage to set initial cookie values
Task.Run(async () => response = await client.GetAsync("/")).GetAwaiter().GetResult(); //200
string urlToPost = "/login/";
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("username", "username"));
postData.Add(new KeyValuePair<string, string>("password", "password"));
HttpContent stringContent = new FormUrlEncodedContent(postData);
client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
client.DefaultRequestHeaders.Add("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36");
client.DefaultRequestHeaders.Add("Origin", "https://www.cdc.co.nz");
client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
client.DefaultRequestHeaders.Add("Connection", "keep-alive");
client.DefaultRequestHeaders.Add("Host", "www.cdc.co.nz");
client.DefaultRequestHeaders.Add("Referer", "https://www.cdc.co.nz/login/");
cookieContainer.Add(baseAddress, new Cookie("_ga", "GA1.3.720299450.1533761418"));
cookieContainer.Add(baseAddress, new Cookie("_gat_oldTracker", "1"));
cookieContainer.Add(baseAddress, new Cookie("_gat", "1"));
cookieContainer.Add(baseAddress, new Cookie("_gid", "GA1.3.1011102476.1533761418"));
//Tyler's suggestion here works!
//cookieContainer.Add(baseAddress, new Cookie("PHPSESSID", "value from browser login response header"));
//Receiving 200 response for the nextline, though it returns a 302 in a browser environment
Task.Run(async () => response = await client.PostAsync(urlToPost, stringContent)).GetAwaiter().GetResult();
//401 response for the next line
Task.Run(async () => response = await client.GetAsync("/products/list.html?cat=5201")).GetAwaiter().GetResult();
}
Fiddler for browser environment:
Result: 302
Protocol: HTTPS
Host: www.cdc.co.nz
URL: /login/
Raw Request Header Browser Environment:
POST /login/ HTTP/1.1
Host: www.cdc.co.nz
Connection: keep-alive
Content-Length: 69
Cache-Control: max-age=0
Origin: https://www.cdc.co.nz
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: https://www.cdc.co.nz/login/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: _ga=GA1.3.720299450.1533761418; _gid=GA1.3.1011102476.1533761418; PHPSESSID=p3jn5qqhcul59blum597mp2o41; _gat=1; _gat_oldTracker=1
Response Raw Header (Set-Cookie: PHPSESSID=oh7in7n5pjbkrkng4qwwwn22uaq951 is what I am interested) in browser environment:
HTTP/1.1 302 Found
Date: Thu, 09 Aug 2018 00:51:11 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.25
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: PHPSESSID=oh7in7n5pjbkrkng4qwwwn22uaq951 <-------- Needed in subsequent Request headers to not 401.
Location: https://www.cdc.co.nz/home/news.html
Content-Length: 0
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
Fiddler for HttpClient:
Result: 200
Protocol: HTTPS
Host: www.cdc.co.nz
URL: /login/
Raw Header in HttpClient environment:
GET /login/ HTTP/1.1
Host: www.cdc.co.nz
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: https://www.cdc.co.nz/home/my-account/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: _ga=GA1.3.720299450.1533761418; _gid=GA1.3.1011102476.1533761418; _gat=1; _gat_oldTracker=1; PHPSESSID=sdjm7r2jge751jo39mkesqnfl6
Raw Response Header in HttpClient environment (notice how there is no Set-Cookie header / value here?):
HTTP/1.1 200 OK
Date: Thu, 09 Aug 2018 01:11:14 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.25
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
Content-Length: 5668
Answer
Adding the extra KV pairs (without even the specification of other unnecessary details) has now got the code working:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
var baseAddress = new Uri("https://www.cdc.co.nz");
using (HttpClient client = new HttpClient() { BaseAddress = baseAddress })
{
HttpResponseMessage response = null;
//Let's visit the homepage to set initial cookie values
Task.Run(async () => response = await client.GetAsync("/")).GetAwaiter().GetResult(); //200
string urlToPost = "/login/";
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("username", "username"));
postData.Add(new KeyValuePair<string, string>("password", "password"));
postData.Add(new KeyValuePair<string, string>("returnUrl", "/login/")); <----- To simulate the browser
postData.Add(new KeyValuePair<string, string>("service", "login")); <----- To simulate the browser
HttpContent stringContent = new FormUrlEncodedContent(postData);
//Receiving 200 response for the nextline, though it returns a 302 in a browser environment
Task.Run(async () => response = await client.PostAsync(urlToPost, stringContent)).GetAwaiter().GetResult();
//200 response now
Task.Run(async () => response = await client.GetAsync("/products/list.html?cat=5201")).GetAwaiter().GetResult();
}
Try to add hidden form values like browser does
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("username", "username"));
postData.Add(new KeyValuePair<string, string>("password", "password"));
postData.Add(new KeyValuePair<string, string>("returnUrl", "/login/"));
postData.Add(new KeyValuePair<string, string>("service", "login"));
You are using GET and the login requires POST by the fiddler from the browser. You need to pass the user and password as forms (FormUrlEncodedContent) as well.
I think you need to set UseCookies = true here..
using (var handler = new HttpClientHandler() {
CookieContainer = cookieContainer ,
UseCookies = true
})
EDIT: Look at the bottom of this post for updates.
My SignalR implementation works perfectly on my local system. But when I deployed it out to my server it doesnt seem to work. Its an MVC project.
My signalR jQuery is as follows:
var clientHub = $.connection.gamehub;
$(function () {
var signalRHubInitialized = false;
var image = $("#Ico");
var count = 0;
initializeSignalRHubStore();
function initializeSignalRHubStore() {
if (signalRHubInitialized)
return;
try {
clientHub.client.broadcastMessage = function (message) {
if (message === "Refresh")
reloadIndexPartial();
};
$.connection.hub.start().done(function () {
clientHub.server.initialize($("#NotifierEntity").val());
signalRHubInitialized = true;
});
} catch (err) {
signalRHubInitialized = false;
}
};
function reloadIndexPartial() {
//$.post('#(Url.Action("LivePartial", "Scrim", null, Request.Url.Scheme))')
var id = $("#SeriesDetail_Id").val();
$.post('/Scrim/LivePartial/' + id)
.done(function (response) {
try {
count = count + 1;
var favicon = new Favico({
animation: 'pop',
image: image
});
favicon.badge(count);
}
catch (exception) {
}
$("#summary-wrapper").html("");
$("#summary-wrapper").html(response);
if (!signalRHubInitialized)
initializeSignalRHubStore();
});
};
});
I downloaded Fiddler to see what was going on:
/signalr/hubs returned a HTTP200
GET http://sitename.com/signalr/hubs HTTP/1.1
Host: sitename.com
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Accept: */*
Referer: http://sitename.com/scrim/Live/2835
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: _gat=1; _ga=GA1.2.1342148401.1475084375; _gid=GA1.2.2092796788.1503865866
negotiate returned at HTTP200
GET http://sitename.com/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22gamehub%22%7D%5D&_=1505151041506 HTTP/1.1
Host: sitename.com
Connection: keep-alive
Accept: text/plain, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Content-Type: application/json; charset=UTF-8
Referer: http://sitename.com/scrim/Live/2835
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: _gat=1; _ga=GA1.2.1342148401.1475084375; _gid=GA1.2.2092796788.1503865866
connect, didnt return anything
GET http://sitename.com/signalr/connect?transport=serverSentEvents&clientProtocol=1.5&connectionToken=S8rqz2NPvVSJxbS1%2FpLm7yHTinGHWK1SnAwh8IfYA%2BP7nVb9RV%2FJzSFsf8Q%2BTv6Z%2Fae%2FIoZKlHKyeTxaEn3obg%2FVViYTB5HZxnrvKvtBZtQopvGPdj1i4o8Z9wGlCz3%2F&connectionData=%5B%7B%22name%22%3A%22gamehub%22%7D%5D&tid=10 HTTP/1.1
Host: sitename.com
Connection: keep-alive
Accept: text/event-stream
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Referer: http://sitename.com/scrim/Live/2835
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: _gat=1; _ga=GA1.2.1342148401.1475084375; _gid=GA1.2.2092796788.1503865866
start returned a HTTP200
GET http://sitename.com/signalr/start?transport=serverSentEvents&clientProtocol=1.5&connectionToken=S8rqz2NPvVSJxbS1%2FpLm7yHTinGHWK1SnAwh8IfYA%2BP7nVb9RV%2FJzSFsf8Q%2BTv6Z%2Fae%2FIoZKlHKyeTxaEn3obg%2FVViYTB5HZxnrvKvtBZtQopvGPdj1i4o8Z9wGlCz3%2F&connectionData=%5B%7B%22name%22%3A%22gamehub%22%7D%5D&_=1505151041507 HTTP/1.1
Host: sitename.com
Connection: keep-alive
Accept: text/plain, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Content-Type: application/json; charset=UTF-8
Referer: http://sitename.com/scrim/Live/2835
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: _gat=1; _ga=GA1.2.1342148401.1475084375; _gid=GA1.2.2092796788.1503865866
Send returned a HTTP200
POST http://sitename.com/signalr/send?transport=serverSentEvents&clientProtocol=1.5&connectionToken=S8rqz2NPvVSJxbS1%2FpLm7yHTinGHWK1SnAwh8IfYA%2BP7nVb9RV%2FJzSFsf8Q%2BTv6Z%2Fae%2FIoZKlHKyeTxaEn3obg%2FVViYTB5HZxnrvKvtBZtQopvGPdj1i4o8Z9wGlCz3%2F&connectionData=%5B%7B%22name%22%3A%22gamehub%22%7D%5D HTTP/1.1
Host: sitename.com
Connection: keep-alive
Content-Length: 2227
Accept: text/plain, */*; q=0.01
Origin: http://sitename.com
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://sitename.com/scrim/Live/2835
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: _gat=1; _ga=GA1.2.1342148401.1475084375; _gid=GA1.2.2092796788.1503865866
data=%7B%22H%22%3A%22gamehub%22%2C%22M%22%3A%22Initialize%22%2C%22A%22%3A%5B%22%7B%5C%22SqlQuery%5C%22%3A%5C%22SELECT+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BId%5D+AS+%5BId%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BGameGuid%5D+AS+%5BGameGuid%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BDate%5D+AS+%5BDate%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BTeamOneScore%5D+AS+%5BTeamOneScore%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BTeamZeroScore%5D+AS+%5BTeamZeroScore%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BTeamOneId%5D+AS+%5BTeamOneId%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BTeamZeroId%5D+AS+%5BTeamZeroId%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BGameVariantId%5D+AS+%5BGameVariantId%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BMapId%5D+AS+%5BMapId%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BDuration%5D+AS+%5BDuration%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BSeriesId%5D+AS+%5BSeriesId%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BResult%5D+AS+%5BResult%5D%2C+%5C%5Cr%5C%5Cn++++%5BExtent1%5D.%5BActive%5D+AS+%5BActive%5D%5C%5Cr%5C%5Cn++++FROM+%5Bdbo%5D.%5BGame%5D+AS+%5BExtent1%5D%5C%5Cr%5C%5Cn++++WHERE+(%5BExtent1%5D.%5BActive%5D+%3D+1)+AND+(%5BExtent1%5D.%5BSeriesId%5D+%3D+%40p__linq__0)%5C%22%2C%5C%22SqlConnectionString%5C%22%3A%5C%22Data+Source%3DWIN-1J1JAEOEU33%3BInitial+Catalog%3DSiteName%3BIntegrated+Security%3DTrue%3BMultipleActiveResultSets%3DTrue%3B%5C%22%2C%5C%22SqlParameters%5C%22%3A%5B%7B%5C%22CompareInfo%5C%22%3A0%2C%5C%22XmlSchemaCollectionDatabase%5C%22%3A%5C%22%5C%22%2C%5C%22XmlSchemaCollectionOwningSchema%5C%22%3A%5C%22%5C%22%2C%5C%22XmlSchemaCollectionName%5C%22%3A%5C%22%5C%22%2C%5C%22DbType%5C%22%3A11%2C%5C%22LocaleId%5C%22%3A0%2C%5C%22ParameterName%5C%22%3A%5C%22p__linq__0%5C%22%2C%5C%22Precision%5C%22%3A0%2C%5C%22Scale%5C%22%3A0%2C%5C%22SqlDbType%5C%22%3A8%2C%5C%22SqlValue%5C%22%3A%7B%5C%22IsNull%5C%22%3Afalse%2C%5C%22Value%5C%22%3A2835%7D%2C%5C%22UdtTypeName%5C%22%3A%5C%22%5C%22%2C%5C%22TypeName%5C%22%3A%5C%22%5C%22%2C%5C%22Value%5C%22%3A2835%2C%5C%22Direction%5C%22%3A1%2C%5C%22IsNullable%5C%22%3Afalse%2C%5C%22Offset%5C%22%3A0%2C%5C%22Size%5C%22%3A0%2C%5C%22SourceColumn%5C%22%3A%5C%22%5C%22%2C%5C%22SourceColumnNullMapping%5C%22%3Afalse%2C%5C%22SourceVersion%5C%22%3A512%7D%5D%7D%22%5D%2C%22I%22%3A0%7D
I have added this to my web config:
<modules runAllManagedModulesForAllRequests="true"></modules>
Looking through all the responses it seems that everything is working correctly but the page Im on is not being updated when a new entry has been added to the database.
On my local development system my project is set up using IIS it works flawlessly.
Could anyone point me in the right direction please.
EDIT: I have got it working on the server now. But it seems that it works right after it has been deployed for a few hours. Then after that it seems to stop working. So I have to assume that the signalr connection is being disposed at some stage and now getting reinstated?
Here is my RegisterServices class:
private static IContainer RegisterServices(ContainerBuilder builder)
{
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<ContextEntities>()
.As<DbContext>()
.InstancePerRequest();
builder.RegisterType<DbFactory>()
.As<IDbFactory>()
.InstancePerRequest();
builder.RegisterType<UnitOfWork>()
.As<IUnitOfWork>()
.InstancePerRequest();
// Services
builder.RegisterType<MembershipService>()
.As<IMembershipService>()
.InstancePerRequest();
builder.RegisterType<CacheService>()
.As<ICacheService>()
.InstancePerRequest();
builder.RegisterType<GameHub>().ExternallyOwned();
Container = builder.Build();
return Container;
}
Here is a page where signalr is used: http://halodatahive.com/Scrim/Live/2845
I seem to be losing reference to the signalr connection after a few hours after a deployment.
EDIT: If I recycle my APP POOL the page with signalR starts working again.
This is what I ended up using to resolve the issue. It seems that after around 1 hour it was getting disconnected some how. I put this code in a few hours ago and it still seems to be working. Thanks to #Noren for all their help in chat earlier!
EDIT: This did not seem to solve the problem unfortunately.
$.connection.hub.disconnected(function() {
setTimeout(function() {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});
EDIT: Thought I would give an update as to how I got this working. Instead of using SqlDependency to trigger the SignalR I just called Clients.All.broadcastMessage("Refresh"); on the scheduled task I have running on the server when _unitOfWork.Commit() was called.
Something was causing SqlDependency to stop working and the only way to get it to pick it up again was to recycle the app pool.
I've seen something like this before. In my case it was RabbitMQ events that were lost because IIS was spinning down the application.
Is your application is not being hit very frequently? IIS has a tendency to spin down applications that it doesn't think it needs in order to save resources. That might be why it only stops working after a few hours and you can recycle to bring it back up.
See this answer.
first add Hubs folder and NotificationsHubs.cs in root
in NotificationsHubs.cs
[HubName("NotificationsHubs")]
public class NotificationsHubs : Hub
{
public static Thread NotificationsThread;
public void Send(string token, string UserAgent, string IP)
{
var serverVars = Context.Request.GetHttpContext().Request.ServerVariables;
string SignalRIp = serverVars["REMOTE_ADDR"];
string T = Context.Request.Headers["User-Agent"].ToLower();
if ((T == cryptClass.crypt.Decrypt(UserAgent)) && (SignalRIp == cryptClass.crypt.Decrypt(IP)))
{
var connection = SignalRConnections.Connections.SingleOrDefault(c => c.Token == Guid.Parse(token));
if (connection != null)
{
connection.Context = this.Context;
}
if (NotificationsThread == null || !NotificationsThread.IsAlive)
{
NotificationsThread = new Thread(new ThreadStart(NotificationsCheck));
NotificationsThread.Start();
}
}
NotificationsCheck is custom function
in NotificationController
public ActionResult Notifications()
{
NotificationsModule.messageBL = _messageBL;
long UserID = GetCurrentUser();
Notification _Notification = new Notification();
_Notification.GetToken = SignalRConnections.GetToken(UserID);
_Notification.UserAgent = cryptClass.crypt.Encrypt(Request.UserAgent.ToLower());
_Notification.IP = cryptClass.crypt.Encrypt(Request.UserHostAddress);
return View(_Notification);
}
in Notifications.cshtml view
add this JS file
<script src="~/Scripts/jquery.signalR-2.2.1.js")"></script>
<script src="~/signalr/hubs"></script>
$(function () {
// Reference the auto-generated proxy for the hub.
var chat = $.connection.NotificationsHubs;
// Create a function that the hub can call back to display messages.
chat.client.addNewMessageToPage = function (Title, Body, Icon) {
// Add the message to the page.
notifyMe(Title, Body, Icon);
};
$.connection.hub.start().done(function () {
chat.server.send('#Model.GetToken', '#Model.UserAgent', '#Model.IP');
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send();
});
});
});
notifyMe(Title, Body, Icon); is jquery custom function
I'm trying to send and $http.get() request and authenticate it in the server side (WebApi)
$http.get(config.remoteServiceUrl + "api/account", {
headers:
{
'Authorization': 'Basic ' + encoded,
'Content-Type': "application/json"
},
params:
{
'email': credentials.Email
}
}).then(
//Success
function (data, status) {
setCredentials(credentials.Email, credentials.Password);
service.user.email = credentials.Email;
loggedin = true;
result.data = data;
result.status = status;
deferred.resolve(result);
},
//Error
function (data, status) {
result.data = data;
result.status = status;
deferred.reject(result);
}
);
for every unauthorized request the server should return a 401 status
HttpResponseMessage reply = request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Invalid Username or Password");
return Task.FromResult(reply);
but when i check the response in the client side the status is always empty instead of the 401 status.
below is the request being sent
Request URL:http://127.0.0.1:81/api/account?email=login#yahoo.com
Request Headersview source
Accept:application/json, text/plain, */*
Authorization:Basic bG9naW5AeWFob28uY29tOjExMTE=
Origin:http://localhost
Referer:http://localhost/EMR.WebUI/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Query String Parametersview sourceview URL encoded
email:login#yahoo.com
when i check the request status after the call in the chrome debugger network tab is says
GET (Cancelled)
Anyone knows why this is happening?
It works correctly when a proper authorization is passed
Request URL:http://127.0.0.1:81/api/account?email=login#yahoo.com
Request Method:GET
Status Code:200 OK
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:fil,fil-PH;q=0.8,tl;q=0.6,en-US;q=0.4,en;q=0.2
Authorization:Basic bG9naW5AeWFob28uY29tOjE=
Connection:keep-alive
Host:127.0.0.1:81
Origin:http://localhost
Referer:http://localhost/EMR.WebUI/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Query String Parametersview sourceview URL encoded
email:login#yahoo.com
Response Headersview source
Access-Control-Allow-Origin:*
Cache-Control:no-cache
Content-Length:110
Content-Type:application/json; charset=utf-8
Date:Mon, 13 Jan 2014 11:00:35 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/8.0
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
I want to sign in to a site when a link is clicked and then redirect the browser there with a signed in session. Im having some troubles and here is what Ive tried:
First I get the session cookies from the login site:
CookieContainer cookies= new CookieContainer();
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://someuri.com");
myHttpWebRequest.CookieContainer = cookies;
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
myHttpWebResponse.Close();
Then I post to the sign in page to get signed in:
HttpWebRequest getRequest = (HttpWebRequest)WebRequest.Create("http://signInURL.com");
getRequest.CookieContainer = cookies;
getRequest.Method = WebRequestMethods.Http.Post;
getRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2";
getRequest.AllowWriteStreamBuffering = true;
getRequest.ProtocolVersion = HttpVersion.Version11;
getRequest.AllowAutoRedirect = true;
getRequest.ContentType = "application/x-www-form-urlencoded";
byte[] byteArray = Encoding.ASCII.GetBytes(PostParameterStringWithSignInInfo);
getRequest.ContentLength = byteArray.Length;
Stream newStream = getRequest.GetRequestStream();
newStream.Write(byteArray, 0, byteArray.Length);
newStream.Close();
HttpWebResponse getResponse = (HttpWebResponse)getRequest.GetResponse();
Then I figured I need to set the cookies to the client:
CookieCollection cooki = getRequest.CookieContainer.GetCookies(new Uri("http://someUri.com"));
for(int i = 0; i < cooki.Count; i++)
{
Cookie c = cooki[i];
Response.Cookies.Add(new HttpCookie(c.Name, c.Value));
}
And then redirect to where you end up being signed in:
Response.Redirect("http://URLwhenBeingSignedIn.com");
This doesnt work. When redirected Im still logged out.
Tried to do this with Fiddler and succeeded to sign in and get redirected:
Get the session cookies:
GET / HTTP/1.1
Content-type: application/x-www-form-urlencoded
Host: someuri.com
Post to the sign in page to get signed in:
POST /signIn HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Referer: http://someuri.com
Accept-Language: en-GB,en;q=0.7,tr;q=0.3
User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Content-Length: 90
DNT: 1
Host: signInURL.com
Pragma: no-cache
Cookie: JSESSIONID=fromBefore; Cookie2=fromBefore
PostParameterStringWithSignInInfo
Perhaps there's an easier way than the one I thought of now that you can see the fiddler requests that works, if so I'm happy to see it.
I've got an issue with the BasicAuthProvider in ServiceStack. POST-ing to the CredentialsAuthProvider (/auth/credentials) is working fine.
The problem is that when GET-ing (in Chrome):
http://foo:pwd#localhost:81/tag/string/list
the following is the result
Handler for Request not found:
Request.HttpMethod: GET
Request.HttpMethod: GET
Request.PathInfo: /login
Request.QueryString: System.Collections.Specialized.NameValueCollection
Request.RawUrl: /login?redirect=http%3a%2f%2flocalhost%3a81%2ftag%2fstring%2flist
which tells me that it redirected me to /login instead of serving the /tag/... request.
Here's the entire code for my AppHost:
public class AppHost : AppHostHttpListenerBase, IMessageSubscriber
{
private ITagProvider myTagProvider;
private IMessageSender mySender;
private const string UserName = "foo";
private const string Password = "pwd";
public AppHost( TagConfig config, IMessageSender sender )
: base( "BM App Host", typeof( AppHost ).Assembly )
{
myTagProvider = new TagProvider( config );
mySender = sender;
}
public class CustomUserSession : AuthUserSession
{
public override void OnAuthenticated( IServiceBase authService, IAuthSession session, IOAuthTokens tokens, System.Collections.Generic.Dictionary<string, string> authInfo )
{
authService.RequestContext.Get<IHttpRequest>().SaveSession( session );
}
}
public override void Configure( Funq.Container container )
{
Plugins.Add( new MetadataFeature() );
container.Register<BeyondMeasure.WebAPI.Services.Tags.ITagProvider>( myTagProvider );
container.Register<IMessageSender>( mySender );
Plugins.Add( new AuthFeature( () => new CustomUserSession(),
new AuthProvider[] {
new CredentialsAuthProvider(), //HTML Form post of UserName/Password credentials
new BasicAuthProvider(), //Sign-in with Basic Auth
} ) );
container.Register<ICacheClient>( new MemoryCacheClient() );
var userRep = new InMemoryAuthRepository();
container.Register<IUserAuthRepository>( userRep );
string hash;
string salt;
new SaltedHash().GetHashAndSaltString( Password, out hash, out salt );
// Create test user
userRep.CreateUserAuth( new UserAuth
{
Id = 1,
DisplayName = "DisplayName",
Email = "as#if.com",
UserName = UserName,
FirstName = "FirstName",
LastName = "LastName",
PasswordHash = hash,
Salt = salt,
}, Password );
}
}
Could someone please tell me what I'm doing wrong with either the SS configuration or how I am calling the service, i.e. why does it not accept the supplied user/pwd?
Update1: Request/Response captured in Fiddler2when only BasicAuthProvider is used.
No Auth header sent in the request, but also no Auth header in the response.
GET /tag/string/AAA HTTP/1.1
Host: localhost:81
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,sv;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: ss-pid=Hu2zuD/T8USgvC8FinMC9Q==; X-UAId=1; ss-id=1HTqSQI9IUqRAGxM8vKlPA==
HTTP/1.1 302 Found
Location: /login?redirect=http%3a%2f%2flocalhost%3a81%2ftag%2fstring%2fAAA
Server: Microsoft-HTTPAPI/2.0
X-Powered-By: ServiceStack/3,926 Win32NT/.NET
Date: Sat, 10 Nov 2012 22:41:51 GMT
Content-Length: 0
Update2 Request/Response with HtmlRedirect = null . SS now answers with the Auth header, which Chrome then issues a second request for and authentication succeeds
GET http://localhost:81/tag/string/Abc HTTP/1.1
Host: localhost:81
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,sv;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: ss-pid=Hu2zuD/T8USgvC8FinMC9Q==; X-UAId=1; ss-id=1HTqSQI9IUqRAGxM8vKlPA==
HTTP/1.1 401 Unauthorized
Transfer-Encoding: chunked
Server: Microsoft-HTTPAPI/2.0
X-Powered-By: ServiceStack/3,926 Win32NT/.NET
WWW-Authenticate: basic realm="/auth/basic"
Date: Sat, 10 Nov 2012 22:49:19 GMT
0
GET http://localhost:81/tag/string/Abc HTTP/1.1
Host: localhost:81
Connection: keep-alive
Authorization: Basic Zm9vOnB3ZA==
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,sv;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: ss-pid=Hu2zuD/T8USgvC8FinMC9Q==; X-UAId=1; ss-id=1HTqSQI9IUqRAGxM8vKlPA==
Prefixing foo:pwd# to a url like:
http://foo:pwd#localhost:81/tag/string/list
is not how you do BasicAuth with HTTP, the wikipedia page for an example:
Sending BasicAuth request with a HTTP client
When the user agent wants to send the server authentication credentials it may use the Authorization header.
The Authorization header is constructed as follows:
Username and password are combined into a string "username:password"
The resulting string literal is then encoded using Base64
The Authorization method and a space i.e. "Basic " is then put before the encoded string.
For example, if the user agent uses 'Aladin' as the username and 'sesam open' as the password then the header is formed as follows:
Authorization: Basic QWxhZGluOnNlc2FtIG9wZW4=