Consider the following ASP.net web api controller method. For demo purpose it returns a cookie. the session-id cookie has a base64 encoded data. When I add the cookie to the response with response.Headers.AddCookies(new CookieHeaderValue[] { cookie }); it url encodes the data (Documentation is here). Is there any way I can attach the cookie without encoding it?
public HttpResponseMessage LogMeIn()
{
var response = Request.CreateResponse<Models.UserAuthResponse>(new Models.UserAuthResponse());
var cookie = new CookieHeaderValue("session-id", "K2QRkQaSnwCBpRrAgI1K3w9kTgbArc+xdIJI64e2hz0=");
cookie.Expires = DateTimeOffset.Now.AddDays(1);
cookie.Domain = ".example.com";
cookie.Path = "/";
response.Headers.AddCookies(new CookieHeaderValue[] { cookie });
return response;
}
I have the same problem because i want to create LTPA Token cookie used by Lotus Domino SSO web applications and this cookie is base64 encoded and use special characters in cookie like "+=....".
I find three way to solve this problem:
OWIN extension in Startup.cs
app.Use((context, next) =>
{
context.Response.Headers....;
//here decode and replace the cookies
return next.Invoke();
});
using javascript after page load with cookies:
document.cookie = encodeURIComponent(document.cookie);
or the best way is to create extension like this:
/// <summary>
///
/// </summary>
public static class CookieExtensions
{
/// <summary>
/// Add a new cookie and value
///
/// </summary>
/// <param name="header"></param>
/// <param name="key"/><param name="value"/>
public static void AppendUrlDecodedCookie(this IHeaderDictionary header, string key, string value)
{
header.AppendValues("Set-Cookie", key + "=" + value + "; path=/");
}
/// <summary>
/// Add a new cookie
///
/// </summary>
/// <param name="header"></param>
/// <param name="key"/><param name="value"/><param name="options"/>
public static void AppendUrlDecodedCookie(this IHeaderDictionary header, string key, string value, CookieOptions options)
{
if (options == null)
throw new ArgumentNullException("options");
bool flag1 = !string.IsNullOrEmpty(options.Domain);
bool flag2 = !string.IsNullOrEmpty(options.Path);
bool hasValue = options.Expires.HasValue;
header.AppendValues("Set-Cookie",
key + "=" + (value ?? string.Empty) + (!flag1 ? (string) null : "; domain=") +
(!flag1 ? (string) null : options.Domain) + (!flag2 ? (string) null : "; path=") +
(!flag2 ? (string) null : options.Path) + (!hasValue ? (string) null : "; expires=") +
(!hasValue
? (string) null
: options.Expires.Value.ToString("ddd, dd-MMM-yyyy HH:mm:ss ",
(IFormatProvider) CultureInfo.InvariantCulture) + "GMT") +
(!options.Secure ? (string) null : "; secure") + (!options.HttpOnly ? (string) null : "; HttpOnly"));
}
}
And you can use it like this:
response.Headers.AppendUrlDecodedCookie("key", "val");
or
response.Headers.AppendUrlDecodedCookie("key", "val", new Microsoft.Owin.CookieOptions
{
Path = "/",
Domain = ="domain.com",
Expires = Date...
});
And this solve the problem.
In a NET Core project, I did an extension method to HttpResponse. In my case, I needed to replace all space characters in order to have a valid cookie value. keep in mind what kind of values you need to save and then update the string properly before creating the setCookieHeaderValue .
public static class CookiesExtensions
{
public static void AppendUnencodedCookie(this HttpResponse response, string key, string value, CookieOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
response.Cookies.Delete(key);
var setCookieHeaderValue = new SetCookieHeaderValue(key, value.Replace(" ","+"))
{
Domain = options.Domain,
Path = options.Path,
Expires = options.Expires,
MaxAge = options.MaxAge,
Secure = options.Secure,
SameSite = (Microsoft.Net.Http.Headers.SameSiteMode)options.SameSite,
HttpOnly = options.HttpOnly
};
response.Headers[HeaderNames.SetCookie] = StringValues.Concat(response.Headers[HeaderNames.SetCookie], setCookieHeaderValue.ToString());
}
}
Use it like this:
Context.Response.AppendUnencodedCookie(cookieName, cookieValue, options);
Related
Amazingly low on doco when it comes to rest api. Can anyone give me a working example of Sugar CRM REST calls using C#?
I was trying out SugarSharp but it's just listing the services and not coming up with Data(null)
Appreciate this is an old question but for anyone else that comes across it, took me a while to get it all working with creating and updating relationships being the toughest to fathom.
Here is part of a wrapper class I wrote around the v4_1 rest api, hope it helps:-
public void Login()
{
object loginData = new
{
user_auth = new
{
user_name = Username,
password = CalculateMD5Hash(Password)
}
};
string jsonData = CreateFormattedPostRequest("login", loginData);
var request = GetRestRequest(jsonData, "POST");
var loginResponse = GetRestResponseByType<LoginResponse>(request);
if (string.IsNullOrEmpty(loginResponse.id))
{
throw new SugarException(string.Concat("Authorisation Failed for user: {0}, did not retrieve access token", Username));
}
SessionID = loginResponse.id;
}
Format the request:-
private string CreateFormattedPostRequest(string method, object data)
{
StringBuilder buffer = new StringBuilder();
using (StringWriter writer = new StringWriter(buffer))
{
serializer.Serialize(data, buffer);
}
string result = "method=" + method;
result += "&input_type=JSON&response_type=JSON&rest_data=" + buffer.ToString();
return result;
}
And finally get the response:-
private object GetRestResponseAsObject(HttpWebRequest request)
{
using (var response = (HttpWebResponse)request.GetResponse())
{
using (Stream input = response.GetResponseStream())
{
StreamReader reader = new StreamReader(input);
string buffer = reader.ReadToEnd();
var responseObj = serializer.DeserializeObject(buffer);
return responseObj;
}
}
}
And here is an example call to the set_entry method:-
/// <summary>
/// Creates or Updates a single bean, for update ensure that the name_value_list contains the ID of the record
/// name_value_lists - Dictionary where the keys of the are the SugarBean attributes (columns), the values of the array are the values the attributes should have.
/// </summary>
/// <param name="module">Module to update i.e Account</param>
/// <param name="record">key value pair object of record, include ID for update</param>
/// <returns>Returns the updated or created Bean ID</returns>
public string CreateUpdateBean(string module, object record)
{
var parameters = new Dictionary<string, object>();
parameters.Add("session", SessionID);
parameters.Add("module_name", module);
parameters.Add("name_value_list", record);
parameters.Add("track_view", false);
string jsonData = CreateFormattedPostRequest("set_entry", parameters);
var request = GetRestRequest(jsonData, "POST");
var result = GetRestResponseByType<object>(request);
return result.ToString();
}
For calling rest api SugarCRM/SuiteCRM with c#, you can use SugarRestSharp
Example for create Account:
var client = new SugarRestClient(TestAccount.Url, TestAccount.Username, TestAccount.Password);
Account insertAccount = AccountsModule.GetTestAccount();
// -------------------Create Account-------------------
SugarRestResponse response = AccountsModule.CreateAccount(client, insertAccount);
Assert.NotNull(response);
Assert.Equal(response.StatusCode, HttpStatusCode.OK);
string insertId = (response.Data == null) ? string.Empty : response.Data.ToString();
Assert.NotNull(insertId);
Assert.NotEmpty(insertId);
// -------------------End Create Account-------------------
I am currently trying to generate a CSV using nhibernate. This error does not occur on my development enviroment but it does on the live site that it's being used on. I have tried fiddling with time out's but this does not seem to have any effect as it's timing out way before it should. The timing is completely random, sometimes it'll be 3 seconds before it times out the next it will be 10 seconds. There doesn't seem to be any real consistancy in the timing.
Stack Trace:
System.Web.HttpException: The remote host closed the connection. The error code is 0x800703E3.
at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)
at System.Web.Hosting.IIS7WorkerRequest.ExplicitFlush()
at System.Web.HttpResponse.Flush(Boolean finalFlush)
at Reports.CustomCSVWriter.WritetoHttpStream(String filename, Boolean header)
The code is as follows:
public class ProductSpreadSheetDownload : CustomCSVWriter
{
protected override string[] GetCollection()
{
Page.Server.ScriptTimeout = 300;
IList<Product> products = new List<Product>();
IStockScheme stockScheme = Fabric.ObjectProvider.Get<IStockScheme>();
ICriteria criteria = CoreHttpModule.Session.CreateCriteria(typeof(Product))
.Add(NHibernate.Expression.Expression.IsNotNull(Product.STOCK_CODE))
.Add(NHibernate.Expression.Expression.Eq(Product.IS_VISIBLE_ON_WEBSITE, true))
.Add(NHibernate.Expression.Expression.Eq(Product.STOCK_TYPE, StockType.StockItem))
.Add(NHibernate.Expression.Expression.Not(NHibernate.Expression.Expression.Like(Product.NAME, "%*%")));
AddCustomCriteria(criteria);
products = criteria.List<Product>();
products = Product.RemoveOrphanedAndUnrooted((List<Product>)products);
Product[] productArray = new Product[products.Count];
products.CopyTo(productArray, 0);
double?[] levels = stockScheme.GetStock(productArray, false);
List<string> productStringList = new List<string>();
IProductMapper mapper = Fabric.ObjectProvider.Get<IProductMapper>();
var rootUrl = Fabric.SettingsProvider.ReadSetting<string>("RootUrl", string.Empty);
string showOutOfStock = Page.Request.QueryString["ShowOutOfStock"];
int minStockLevel = int.MinValue;
if (showOutOfStock == "False")
minStockLevel = 0;
for (int i = 0; i < productArray.Length; i++)
{
if (levels[i] > minStockLevel && levels[i] != null && productArray[i].Parent != null && productArray[i].Parent.IsVisibleOnWebsite)
{
StringBuilder productStringBuilder = new StringBuilder();
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].Name));
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].StockCode));
productStringBuilder.AppendFormat("{0}, ", levels[i]);
productStringBuilder.AppendFormat("{0}, ", mapper.GetUrl(productArray[i]) );
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].Category));
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].SubCategory));
productStringBuilder.AppendFormat("{0}, ", CleanString(mapper.GetText(productArray[i], "Description")));
productStringBuilder.AppendFormat("{0}, ", mapper.GetImageUrl(productArray[i], "Main"));
AddCustomFields(productStringBuilder, mapper);
productStringList.Add(productStringBuilder.ToString().Trim().TrimEnd(','));
}
}
string[] productstrings = new string[productStringList.Count];
productStringList.CopyTo(productstrings, 0);
return productstrings;
}
/// <summary>
/// Override this method to add custom criteria to the feed
/// </summary>
/// <example>
/// criteria.Add(NHibernate.Expression.Expression.Eq(Product.IS_VISIBLE_ON_WEBSITE, true));
/// </example>
protected virtual void AddCustomCriteria(ICriteria criteria) {}
/// <summary>
/// Override this method to add custom fields to the CSV output
/// </summary>
/// <example>
/// productStringBuilder.AppendFormat("{0}, ", mapper.GetImageUrl(productArray[i], "Main"));
/// </example>
protected virtual void AddCustomFields(StringBuilder productStringBuilder, IProductMapper mapper) { }
protected override string Headers()
{
string headers = "Name, Stockcode, Stock_Level, URL, Category, SubCategory, Description, Main Image URL";
return headers;
}
/// <summary>
/// Removes characters that are not safe in a CSV file.
/// </summary>
protected static string CleanString(string stringToClean)
{
return string.IsNullOrEmpty(stringToClean) ? string.Empty : stringToClean.Replace("\n", " ").Replace(',', ' ');
}
}
}
I'm using JQuery.Cookie to store a javascript object as a cookie value:
var refinerData = {};
// Read in the current cookie if it exists:
if ($.cookie('RefinerData') != null) {
refinerData = JSON.parse($.cookie('RefinerData'));
}
// Set new values based on the category and filter passed in
switch(category)
{
case "topic":
refinerData.Topic = filterVal;
break;
case "class":
refinerData.ClassName = filterVal;
break;
case "loc":
refinerData.Location = filterVal;
break;
}
// Save the cookie:
$.cookie('RefinerData', JSON.stringify(refinerData), { expires: 1, path: '/' });
When I debug in firebug, the value of the cookie value seems to be formatted correctly:
{"Topic":"Disease Prevention and Management","Location":"Hatchery Hill Clinic","ClassName":"I have Diabetes, What can I Eat?"}
I'm writing a SharePoint web part in C# that reads the cookie in and parses it:
protected void Page_Load(object sender, EventArgs e)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies["RefinerData"];
if (cookie != null)
{
string val = cookie.Value;
// Deserialize JSON cookie:
JavaScriptSerializer serializer = new JavaScriptSerializer();
var refiners = serializer.Deserialize<Refiners>(cookie.Value);
output.AppendLine("Deserialized Topic = " + refiners.Topic);
output.AppendLine("Cookie exists: " + val);
}
}
I have a Refiners class for serializing to:
public class Refiners
{
public string Topic { get; set; }
public string ClassName { get; set; }
public string Location { get; set; }
}
However, this code throws an "Invalid JSON Primitive" error. I can't figure out why this isn't working. One possibility is that its not reading the cookie correctly. When I print out the value of the cookie as a string, I get:
%7B%22Topic%22%3A%22Disease%20Prevention%20and%20Management%22%2C%22Class%22%3A%22Childbirth%20%26%20Parenting%202013%22%2C%22Location%22%3A%22GHC%20East%20Clinic%22%7D
Appears URL encoded, try decoding the value using the UrlDecode method of the HtmlUtility (of which an instance is exposed by a page through the Server property):
var refiners = serializer.Deserialize<Refiners>(Server.UrlDecode(cookie.Value));
I think you need to decode the cookie prior to deserialization. Try using;
Refiners refiners = serializer.Deserialize<Refiners>(Server.UrlDecode(cookie.Value));
What is the way to refresh authorization token while a large file is uploading to Google Drive?
For example: expiration time of the current authorization token is "06:00 AM". The file uploading started at "05:15 AM". So at "06:00 AM" the application get exception due authorization token is invalid.
I've tried to around the issue with the below source code, but it does not work.
/// <summary>
/// Uploads a file with a specified path.
/// </summary>
/// <param name="startFolder">The start folder.</param>
/// <param name="path">The path of destination file.</param>
/// <param name="localFile">The local file to upload.</param>
/// <returns>The uploaded file.</returns>
private File GdUploadFile(File startFolder, string path, FileInfo localFile)
{
if (startFolder == null)
{
throw new ArgumentNullException("startFolder");
}
if (localFile == null)
{
throw new ArgumentNullException("localFile");
}
if (!localFile.Exists)
{
throw new FileNotFoundException("File not found", localFile.FullName);
}
var config = GetConfiguration();
if (config.TraceLog)
{
Destination.Logger.LogDebug(string.Format("{0} \tUpload file \"{1}\" to \"{2}\"", Destination.Name, localFile.FullName, path));
}
string pathToFile = string.IsNullOrEmpty(path) ? localFile.Name : path;
string remotePath = ExtractFilePath(pathToFile);
var fileFolder = GdCreateFolderByPath(startFolder, remotePath);
var fileName = ExtractFileName(pathToFile);
DriveService service = GetDriveService();
var body = new File
{
Title = fileName,
Description = "My File",
MimeType = BackupFileMimeType,
Kind = DriveFileKindType,
OriginalFilename = fileName,
FileExtension = localFile.Extension,
Parents = new List<ParentReference>
{
new ParentReference
{
ETag = fileFolder.ETag,
Id = fileFolder.Id,
Kind = fileFolder.Kind
}
}
};
FilesResource.InsertMediaUpload request;
var source = new MediaFileSource(localFile.FullName, BackupFileMimeType);
using (var fileStream = source.GetDataStream())
{
if (config.TraceLog)
{
Destination.Logger.LogDebug(string.Format("{0} \tUploading \"{1}\"...", Destination.Name, localFile.FullName));
}
request = service.Files.Insert(body, fileStream, body.MimeType);
if (config.TraceLog)
{
int postedPercent = 0;
request.ProgressChanged += p =>
{
var currentPercent = (int) (p.BytesSent/(double) source.ContentLength*100);
if (currentPercent != postedPercent)
{
string msg = string.Format("{0} \tPosted {1}% ({2} bytes)", Destination.Name,
currentPercent, p.BytesSent);
Destination.Logger.LogDebug(msg);
postedPercent = currentPercent;
}
};
}
var connection = Destination.Connection as GoogleDriveDestinationConnection;
Debug.Assert(connection != null, "connection != null");
request.ProgressChanged += p =>
{
bool refreshAuth = connection.ForceRefreshAuthorization();
var auth =
request.Authenticator as
Google.Apis.Authentication.OAuth2.OAuth2Authenticator<NativeApplicationClient>;
if (auth != null && auth.State != null && refreshAuth)
{
var state = connection.AuthorizationState;
auth.State.AccessToken = state.AccessToken;
auth.State.AccessTokenExpirationUtc = state.AccessTokenExpirationUtc;
auth.State.AccessTokenIssueDateUtc = state.AccessTokenIssueDateUtc;
auth.State.Callback = state.Callback;
auth.State.RefreshToken = state.RefreshToken;
auth.State.SaveChanges();
if (config.TraceLog)
{
Destination.Logger.LogDebug("Authorization state for the upload request is updated");
}
}
};
request.ChunkSize = ChunkSize;
request.Upload();
if (config.TraceLog)
{
Destination.Logger.LogDebug(string.Format("{0} \t\"{1}\" uploaded", Destination.Name, localFile.FullName));
}
}
return request.ResponseBody;
}
Consider doing Resumable upload (https://developers.google.com/drive/manage-uploads#resumable). Refresh the token when needed and continue the upload where you left off.
I was not able to find a satisfactory solution to the problem of invalid authorization token.
So I have created my own open source lightweight library for working with files on Google Drive. The library invokes all REST functions directly and have full control over uploading or downloading processes. It resolves the problem by refreshing the authorization token every hour. The library is currently in use in thousands of installations of my company’s Sql Server backup product, it is very stable and has successfully resolved this problem. You can take the source code and examples from here: https://github.com/AlexeyVlg/Pranas.Net.Clouds
Here's what's going on. I have an ASP.NET MVC 4 Web API web application. I can call API resources via URL. One of these functions get performance monitoring data for a specified amount of time and returns it in JSON once it has completed. However, what I want to do is return
It is IMPORTANT to note that I am working with a the browser and API resources in the model, not with a View. Please don't casually tell me to use Javascript in a View, because there is no view, or tell me to look at the SignalR wiki because the information for ".NET" sections is meant for desktop applications, not web apps. For example, you can't "Console.WriteLine()" to a browser.
To reiterate, I am using ASP.NET MVC 4 Web API to develop an API, and am calling the API via URL in the browser and it is returning JSON. I am attempting to use SignalR to have the app send JSON to the browser, but it is not doing anything at all. Rather, the application simply returns the completed JSON from the controller action with all of the performance data values once the process has completed. In other words, SignalR is not working.
So what I'm trying to do is while the API resource is gathering all the information, SignalR sends JSON to the browser every second so that the client can see what's going on in real time.
What I need to find out is why SignalR isn't sending it, and how I can send information to be displayed in the browser without Javascript, since I'm working from a model class, not from a view.
As you can see, I subscribe to the event using On, and then use Invoke to call the server-side hub method SendToClient.
Please let me know if I'm trying to do is impossible. I have never heard of a "real-time", dynamic API call via URL.
Here is my hub class. It is located in ~/signalr/hubs and is in a file called LiveHub.cs. The method Send is what I am trying to invoke in the method seen in the next code block.
namespace PerfMon2.signalr.hubs
{
public class LiveHub : Hub
{
public void SendToClient(List<DataValueInfo> json)
{
Clients.showValue(json);
}
}
}
Here is the method from LogDBRepository.cs that includes the SignalR calls.
public List<LogInfo> LogTimedPerfData(string macName, string categoryName, string counterName,
string instanceName, string logName, string live, long? seconds)
{
iModsDBRepository modsDB = new iModsDBRepository();
List<MachineInfo> theMac = modsDB.GetMachineByName(macName);
if (theMac.Count == 0)
return new List<LogInfo>();
else if (instanceName == null)
{
if (!PerformanceCounterCategory.Exists(categoryName, macName) ||
!PerformanceCounterCategory.CounterExists(counterName, categoryName, macName) )
{
return new List<LogInfo>();
}
}
else if (instanceName != null)
{
if (!PerformanceCounterCategory.Exists(categoryName, macName) ||
!PerformanceCounterCategory.CounterExists(counterName, categoryName, macName) ||
!PerformanceCounterCategory.InstanceExists(instanceName, categoryName, macName))
{
return new List<LogInfo>();
}
}
else if (logName == null)
{
return new List<LogInfo>();
}
// Check if entered log name is a duplicate for the authenticated user
List<LogInfo> checkDuplicateLog = this.GetSingleLog(logName);
if (checkDuplicateLog.Count > 0)
{
return new List<LogInfo>();
}
PerformanceCounterCategory category = new PerformanceCounterCategory(categoryName, theMac[0].MachineName);
if (category.CategoryName == null || category.MachineName == null)
{
return new List<LogInfo>();
}
List<LogInfo> logIt = new List<LogInfo>();
if (category.CategoryType != PerformanceCounterCategoryType.SingleInstance)
{
List<InstanceInfo> instances = modsDB.GetInstancesFromCatMacName(theMac[0].MachineName, category.CategoryName);
foreach (InstanceInfo inst in instances)
{
if (!category.InstanceExists(inst.InstanceName))
{
continue;
}
else if (inst.InstanceName.Equals(instanceName, StringComparison.OrdinalIgnoreCase))
{
PerformanceCounter perfCounter = new PerformanceCounter(categoryName, counterName,
inst.InstanceName, theMac[0].MachineName);
//CounterSample data = perfCounter.NextSample();
//double value = CounterSample.Calculate(data, perfCounter.NextSample());
string data = "";
List<UserInfo> currUser = this.GetUserByName(WindowsIdentity.GetCurrent().Name);
string timeStarted = DateTime.Now.ToString("MM/dd/yyyy - h:mm:ss tt");
//string[] dataValues = new string[(int)seconds];
List<string> dataValues = new List<string>();
var hubConnection = new HubConnection("http://localhost/PerfMon2/");
hubConnection.Credentials = CredentialCache.DefaultNetworkCredentials;
var perfMon = hubConnection.CreateProxy("LiveHub");
// perfMon.On("sendValue", message => Console.WriteLine(message));
perfMon.On("showValue", json => Console.WriteLine(json));
hubConnection.Start().Wait();
List<DataValueInfo> lol = new List<DataValueInfo>();
for (int i = 0; i < seconds; i++)
{
data = "Value " + i + ": " + perfCounter.NextValue().ToString();
//dataValues[i] = data;
dataValues.Add(data);
lol.Add(new DataValueInfo
{
Value = perfCounter.NextValue().ToString()
});
// perfMon.Invoke<List<DataValueInfo>>("Send", lol);
perfMon.Invoke("SendToClient", lol);
Thread.Sleep(1000);
}
string timeFinished = DateTime.Now.ToString("MM/dd/yyyy - h:mm:ss tt");
Log log = new Log
{
LogName = logName,
CounterName = perfCounter.CounterName,
InstanceName = perfCounter.InstanceName,
CategoryName = perfCounter.CategoryName,
MachineName = perfCounter.MachineName,
TimeStarted = timeStarted,
TimeFinished = timeFinished,
PerformanceData = string.Join(",", dataValues),
UserID = currUser[0].UserID
};
this.CreateLog(log);
logIt.Add(new LogInfo
{
LogName = logName,
CounterName = perfCounter.CounterName,
InstanceName = perfCounter.InstanceName,
CategoryName = perfCounter.CategoryName,
MachineName = perfCounter.MachineName,
TimeStarted = timeStarted,
TimeFinished = timeFinished,
PerformanceData = dataValues.ToList<string>()
});
break;
}
}
}
else
{
PerformanceCounter perfCounter = new PerformanceCounter(categoryName, counterName,
"", theMac[0].MachineName);
string data = "";
List<UserInfo> currUser = this.GetUserByName(WindowsIdentity.GetCurrent().Name);
string timeStarted = DateTime.Now.ToString("MM/dd/yyyy - h:mm:ss tt");
//string[] dataValues = new string[(int)seconds];
List<string> dataValues = new List<string>();
var hubConnection = new HubConnection("http://localhost/PerfMon2/");
hubConnection.Credentials = CredentialCache.DefaultNetworkCredentials;
var perfMon = hubConnection.CreateProxy("LiveHub");
// perfMon.On("sendValue", message => Console.WriteLine(message));
perfMon.On("showValue", json => Console.WriteLine(json));
hubConnection.Start().Wait();
List<DataValueInfo> lol = new List<DataValueInfo>();
for (int i = 0; i < seconds; i++)
{
data = "Value " + i + ": " + perfCounter.NextValue().ToString();
//dataValues[i] = data;
dataValues.Add(data);
lol.Add(new DataValueInfo
{
Value = perfCounter.NextValue().ToString()
});
// perfMon.Invoke<List<DataValueInfo>>("Send", lol);
perfMon.Invoke("SendToClient", lol);
Thread.Sleep(1000);
}
string timeFinished = DateTime.Now.ToString("MM/dd/yyyy - h:mm:ss tt");
Log log = new Log
{
LogName = logName,
CounterName = perfCounter.CounterName,
InstanceName = perfCounter.InstanceName,
CategoryName = perfCounter.CategoryName,
MachineName = perfCounter.MachineName,
TimeStarted = timeStarted,
TimeFinished = timeFinished,
PerformanceData = string.Join(",", dataValues),
UserID = currUser[0].UserID
};
this.CreateLog(log);
logIt.Add(new LogInfo
{
LogName = logName,
CounterName = perfCounter.CounterName,
InstanceName = perfCounter.InstanceName,
CategoryName = perfCounter.CategoryName,
MachineName = perfCounter.MachineName,
TimeStarted = timeStarted,
TimeFinished = timeFinished,
PerformanceData = dataValues.ToList<string>()
});
}
return logIt;
}
Here is the controller for the method in LogController.cs :
[AcceptVerbs("GET", "POST")]
public List<LogInfo> Log_Perf_Data(string machine_name, string category_name, string counter_name, string instance_name,
string log_name, long? seconds, string live, string enforceQuery)
{
LogController.CheckUser();
// POST api/log/post_data?machine_name=&category_name=&counter_name=&instance_name=&log_name=&seconds=
if (machine_name != null && category_name != null && counter_name != null && log_name != null && seconds.HasValue && enforceQuery == null)
{
List<LogInfo> dataVal = logDB.LogTimedPerfData(machine_name, category_name, counter_name, instance_name,
log_name, live, seconds);
logDB.SaveChanges();
return dataVal;
}
return new List<LogInfo>();
}
Maybe you can implement it in push technique. Here is how I do it:
Class with message
public class Message
{
/// <summary>
/// The name who will receive this message.
/// </summary>
public string RecipientName { get; set; }
/// <summary>
/// The message content.
/// </summary>
public string MessageContent { get; set; }
}
Class that will represent client:
public class Client
{
private ManualResetEvent messageEvent = new ManualResetEvent(false);
private Queue<Message> messageQueue = new Queue<Message>();
/// <summary>
/// This method is called by a sender to send a message to this client.
/// </summary>
/// <param name="message">the new message</param>
public void EnqueueMessage(Message message)
{
lock (messageQueue)
{
messageQueue.Enqueue(message);
// Set a new message event.
messageEvent.Set();
}
}
/// <summary>
/// This method is called by the client to receive messages from the message queue.
/// If no message, it will wait until a new message is inserted.
/// </summary>
/// <returns>the unread message</returns>
public Message DequeueMessage()
{
// Wait until a new message.
messageEvent.WaitOne();
lock (messageQueue)
{
if (messageQueue.Count == 1)
{
messageEvent.Reset();
}
return messageQueue.Dequeue();
}
}
}
Class to send messages to clients:
public class ClientAdapter
{
/// <summary>
/// The recipient list.
/// </summary>
private Dictionary<string, Client> recipients = new Dictionary<string,Client>();
/// <summary>
/// Send a message to a particular recipient.
/// </summary>
public void SendMessage(Message message)
{
if (recipients.ContainsKey(message.RecipientName))
{
Client client = recipients[message.RecipientName];
client.EnqueueMessage(message);
}
}
/// <summary>
/// Called by a individual recipient to wait and receive a message.
/// </summary>
/// <returns>The message content</returns>
public string GetMessage(string userName)
{
string messageContent = string.Empty;
if (recipients.ContainsKey(userName))
{
Client client = recipients[userName];
messageContent = client.DequeueMessage().MessageContent;
}
return messageContent;
}
/// <summary>
/// Join a user to the recipient list.
/// </summary>
public void Join(string userName)
{
recipients[userName] = new Client();
}
/// <summary>
/// Singleton pattern.
/// This pattern will ensure there is only one instance of this class in the system.
/// </summary>
public static ClientAdapter Instance = new ClientAdapter();
private ClientAdapter() { }
}
Sending messages:
Message message = new Message
{
RecipientName = tbRecipientName.Text.Trim(),
MessageContent = tbMessageContent.Text.Trim()
};
if (!string.IsNullOrWhiteSpace(message.RecipientName) && !string.IsNullOrEmpty(message.MessageContent))
{
// Call the client adapter to send the message to the particular recipient instantly.
ClientAdapter.Instance.SendMessage(message);
}
Receive messages (this is JavaScript functions written in test page. They render content of the message on ASPX page. Here you should implement your logic):
// This method will persist a http request and wait for messages.
function waitEvent() {
CSASPNETReverseAJAX.Dispatcher.WaitMessage("<%= Session["userName"] %>",
function (result) {
displayMessage(result);
// Keep looping.
setTimeout(waitEvent, 0);
}, function () {
// Keep looping.
setTimeout(waitEvent, 0);
});
}
// Append a message content to the result panel.
function displayMessage(message) {
var panel = document.getElementById("<%= lbMessages.ClientID %>");
panel.innerHTML += currentTime() + ": " + message + "<br />";
}
// Return a current time string.
function currentTime() {
var currentDate = new Date();
return currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds();
}