Get Progress To Angular 4 from Async C# Method - c#

it tries to upload excel file from angular to the c# async method and read it
and return the progress to angular until it finishes but it's not working
but it keeps stop in first return
any way to fix it and return my pertc to angular HTTP post
my c# code is
[HttpPost("[action]")]
public async Task<IActionResult> UploadFiles(IFormFile files)
{
string hresult = "done";
string message = "uploaded Successfully";
try
{
Stream stream = files.OpenReadStream();
var binaryReader = new BinaryReader(stream);
var fileContent = binaryReader.ReadBytes((int)files.Length);
MemoryStream ms = new MemoryStream(fileContent);
using (ExcelPackage package = new ExcelPackage(ms))
{
StringBuilder sb = new StringBuilder();
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int rowCount = worksheet.Dimension.Rows;
int ColCount = worksheet.Dimension.Columns;
bool bHeaderRow = true;
int tempCount = 0;
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= ColCount; col++)
{
if (bHeaderRow)
{
sb.Append(worksheet.Cells[row, col].Value.ToString() + "\t");
}
else
{
sb.Append(worksheet.Cells[row, col].Value.ToString() + "\t");
}
var pertc = tempCount * 100 / rowCount;
tempCount++;
var progresult = new ObjectResult(pertc)
{
StatusCode = (int)HttpStatusCode.OK
};
Request.HttpContext.Response.Headers.Add("X-Total-Count", "Working");
return progresult;
}
sb.Append(Environment.NewLine);
}
}
}
catch (Exception ex)
{
hresult = ex.Message;
}
var result = new ObjectResult(message)
{
StatusCode = (int)HttpStatusCode.OK
};
Request.HttpContext.Response.Headers.Add("X-Total-Count", hresult);
return result;
}
and I call it from angular like this
const fileBrowser = this.fileInput.nativeElement;
if (fileBrowser.files && fileBrowser.files[0]) {
const formData = new FormData();
formData.append('files', fileBrowser.files[0]);
this.http.post('/api/Main/UploadFiles', formData)
.subscribe(
res => {
console.log(res);
},
err => {
console.log("Error occured");
}
);
any way to get the percentage from async c# method to get it in angular

It's not possible with HTTP calls, as they allow only one response per request and the server does not know about any clients.
If you want your angular app to actively receive messages from a server than you have to use WebSockets on both the front-end and your back-end. There are several tutorials showing angular services which provide simple solutions, unfortunally can't say much about C# site.
Else you could poll (HTTP GET) the current status of process in an interval, which is of cause not perfecly accurate but probably the easiest solution.

Use OkObjectResult Ok method in this way return Ok(progresult);
For example:
[HttpPost("[action]")]
public async Task<IActionResult> UploadFiles(IFormFile files)
{
string hresult = "done";
string message = "uploaded Successfully";
try
{
Stream stream = files.OpenReadStream();
var binaryReader = new BinaryReader(stream);
var fileContent = binaryReader.ReadBytes((int)files.Length);
MemoryStream ms = new MemoryStream(fileContent);
using (ExcelPackage package = new ExcelPackage(ms))
{
StringBuilder sb = new StringBuilder();
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int rowCount = worksheet.Dimension.Rows;
int ColCount = worksheet.Dimension.Columns;
bool bHeaderRow = true;
int tempCount = 0;
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= ColCount; col++)
{
if (bHeaderRow)
{
sb.Append(worksheet.Cells[row, col].Value.ToString() + "\t");
}
else
{
sb.Append(worksheet.Cells[row, col].Value.ToString() + "\t");
}
var pertc = tempCount * 100 / rowCount;
tempCount++;
var progresult = new ObjectResult(pertc)
{
StatusCode = (int)HttpStatusCode.OK
};
Request.HttpContext.Response.Headers.Add("X-Total-Count", "Working");
return Ok(progresult);
}
sb.Append(Environment.NewLine);
}
}
}
catch (Exception ex)
{
hresult = ex.Message;
}
var result = new ObjectResult(message)
{
StatusCode = (int)HttpStatusCode.OK
};
Request.HttpContext.Response.Headers.Add("X-Total-Count", hresult);
return Ok(result);
}
On Angular .ts file:
this.http.post('/api/Main/UploadFiles', formData)
.map((res: Response) =>
{
console.log(res);
})
.catch(error =>
{
console.log("Error occured");
});
}

Related

C# ClientWebSocket not receiving all packets?

I've built a windows service that subscribes to around 10,000 stock tickers in real-time using ClientWebSocket. If I subscribe to 1,000 tickers I receive all the data points as I should (receiving few hundred messages a second), as soon as I get up to 2,000 tickers I don't seem to be receiving the data I should be, 10,000 (receiving thousands of messages a second) its even worse. I've run comparison reports and it looks like I'm losing up to 60% of the packets. I've talked to polygon (the provider of the real-time data) about this issue and they claim their Socket is a firehose and everything that should go out, goes out, and that none of their other clients are complaining. So the only logical thing here would to be to assume its my code, or some limitation. Maybe it's the Task portion of the Receive method? Maybe window's has a max task limitation and I'm exceeding it.
I've also tested this on a high powered dedicated server with 10gb connection so it doesnt seem to be a connection or hardware limitation.
I've also by passed my BlockingCollection cache and the problem still persisted.
Hopefully one of you has some insight, thank you!
Here's my code:
public static ConcurrentDictionary<string, TradeObj> TradeFeed = new ConcurrentDictionary<string, TradeObj>();
public static ConcurrentDictionary<string, QuoteObj> QuoteFeed = new ConcurrentDictionary<string, QuoteObj>();
public static ConcurrentDictionary<string, AggObj> AggFeed = new ConcurrentDictionary<string, AggObj>();
public static BlockingCollection<byte[]> packets = new BlockingCollection<byte[]>();
private static void Start(string[] args)
{
try
{
Polygon.StartSub();
int HowManyConsumers = 2;
for (int i = 0; i < HowManyConsumers; i++)
{
Task.Factory.StartNew(Polygon.ConsumePackets);
}
} catch(Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadKey();
}
public static async Task StartSub()
{
do
{
using (var socket = new ClientWebSocket())
try
{
// socket.Options.KeepAliveInterval = TimeSpan.Zero;
var Connection = "wss://socket.polygon.io/stocks";
await socket.ConnectAsync(new Uri(Connection), CancellationToken.None);
Console.WriteLine("Websocket opened to Polygon.");
await Send(socket, "{\"action\":\"auth\",\"params\":\""+ConfigurationManager.AppSettings["PolygonAPIToken"]+"\"}");
List<List<string>> batches = new List<List<string>>();
for (int i = 0; i < FeedCache.Tickers.Count(); i += 500)
{
var tempList = new List<string>();
tempList.AddRange(FeedCache.Tickers.Skip(i).Take(500));
batches.Add(tempList);
}
int bNum = 0;
string[] quoteStrings = new string[batches.Count()];
foreach (var tList in batches)
{
var tQuery = "";
tQuery = tQuery + "T." + string.Join(",T.", tList.ToArray());
tQuery = tQuery + ",A." + string.Join(",A.", tList.ToArray());
tQuery = tQuery + ",Q." + string.Join(",Q.", tList.ToArray());
quoteStrings[bNum] = tQuery;
bNum++;
}
for (int i = 0; i < quoteStrings.Count(); i++)
{
string SubscribeString = "{\"action\":\"subscribe\",\"params\":\"" + quoteStrings[i] + "\"}";
await Send(socket, SubscribeString);
}
await Receive(socket);
}
catch (Exception ex)
{
Console.WriteLine($"ERROR - {ex.Message}");
Console.WriteLine(ex.ToString());
}
} while (true);
}
static async Task Send(ClientWebSocket socket, string data)
{
var segment = new ArraySegment<byte>(Encoding.UTF8.GetBytes(data));
await socket.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None);
}
static async Task Receive(ClientWebSocket socket)
{
do {
WebSocketReceiveResult result;
var buffer = new ArraySegment<byte>(new byte[2000]);
using (var ms = new MemoryStream())
{
do
{
result = await socket.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
} while (!result.EndOfMessage);
if (result.MessageType == WebSocketMessageType.Close)
{
await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Closed in server by the client", CancellationToken.None);
Console.WriteLine("Socket disconnecting, trying to reconnect.");
await StartSub();
}
else
{
packets.Add(ms.ToArray());
}
}
} while (true);
}
public static async void ConsumePackets()
{
foreach (var buffer in packets.GetConsumingEnumerable())
{
using (var ms = new MemoryStream(buffer))
{
ms.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(ms, Encoding.UTF8))
{
var data = await reader.ReadToEndAsync();
try
{
var j = JArray.Parse(data);
if (j != null)
{
string id = (string)j[0]["ev"];
switch (id)
{
case "T":
AddOrUpdateTrade((string)j[0]["sym"], j);
break;
case "Q":
AddOrUpdateQuote((string)j[0]["sym"], j);
break;
case "A":
AddOrUpdateAgg((string)j[0]["sym"], j);
break;
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
}
public static void AddOrUpdateTrade(string ticker, JArray data)
{
TradeFeed.AddOrUpdate(ticker, new TradeObj {
LastPrice = (double)data[0]["p"],
TradeCount = 1
}, (key, existingVal) =>
{
return new TradeObj {
LastPrice = (double)data[0]["p"],
TradeCount = existingVal.TradeCount + 1,
PriceDirection = (double)data[0]["p"] < existingVal.LastPrice ? "D" : "U"
};
});
}
public static void AddOrUpdateAgg(string ticker, JArray data)
{
AggFeed.AddOrUpdate(ticker, new AggObj
{
TickVolume = (long)data[0]["v"],
VolumeShare = (long)data[0]["av"],
OpenPrice = (double)data[0]["op"],
TickAverage = (double)data[0]["a"],
VWAP = (double)data[0]["vw"],
TickClosePrice = (double)data[0]["c"],
TickHighPrice = (double)data[0]["h"],
TickLowPrice = (double)data[0]["l"],
TickOpenPrice = (double)data[0]["o"]
}, (key, existingVal) =>
{
return new AggObj
{
TickVolume = (long)data[0]["v"],
VolumeShare = (long)data[0]["av"],
OpenPrice = (double)data[0]["op"],
TickAverage = (double)data[0]["a"],
VWAP = (double)data[0]["vw"],
TickClosePrice = (double)data[0]["c"],
TickHighPrice = (double)data[0]["h"],
TickLowPrice = (double)data[0]["l"],
TickOpenPrice = (double)data[0]["o"]
};
});
}
public static void AddOrUpdateQuote(string ticker, JArray data)
{
QuoteFeed.AddOrUpdate(ticker, new QuoteObj
{
BidPrice = (double)data[0]["bp"],
BidSize = (double)data[0]["bs"],
AskPrice = (double)data[0]["ap"],
AskSize = (double)data[0]["as"]
}, (key, existingVal) =>
{
return new QuoteObj
{
BidPrice = (double)data[0]["bp"],
BidSize = (double)data[0]["bs"],
AskPrice = (double)data[0]["ap"],
AskSize = (double)data[0]["as"]
};
});
}

HttpMapTileDataSource.AdditionalRequestHeaders does not add to the request header

I'm adding request headers with the following code example, and I'm expecting to see the information I've added in the request header.
When I follow and review the request header (Telerik Fiddler 4) I can not see the information I added.
I don't know what's wrong with the code. Can you help me?
Thank you in advance.
private HttpMapTileDataSource _dataSource;
public GmHttpTileDataSourceFactory()
{
_dataSource = new
HttpMapTileDataSource("https://tile.openstreetmap.org/{zoomlevel}/{x}/{y}.png");
_dataSource.AdditionalRequestHeaders.Add("Accept-Language", "en");
_dataSource.AdditionalRequestHeaders.Add("Key", "Value");
_dataSource.AdditionalRequestHeaders.Add("blabla", "blabla");
}
Here is a semi-finished code, perhaps to solve the request header problem you encountered.
public class CustomTileDataSource : CustomMapTileDataSource
{
private string _tileUrl;
public Dictionary<string, string> AdditionalRequestHeaders = new Dictionary<string, string>();
private Dictionary<string, string> DefaultRequestHeaders = new Dictionary<string, string>();
public CustomTileDataSource(string tileUrl)
{
_tileUrl = tileUrl;
DefaultRequestHeaders.Add("Cache-Control", "max-age=0");
DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7");
DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
DefaultRequestHeaders.Add("User-Agent", "ozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.10 Safari/537.36 Edg/77.0.235.5");
BitmapRequested += BitmapRequestedHandler;
}
private async void BitmapRequestedHandler(CustomMapTileDataSource sender, MapTileBitmapRequestedEventArgs args)
{
var deferral = args.Request.GetDeferral();
try
{
using (var imgStream = await GetTileAsStreamAsync(args.X, args.Y, args.ZoomLevel))
{
var memStream = imgStream.AsRandomAccessStream();
var decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(memStream);
var pixelProvider = await decoder.GetPixelDataAsync(Windows.Graphics.Imaging.BitmapPixelFormat.Rgba8, Windows.Graphics.Imaging.BitmapAlphaMode.Straight, new Windows.Graphics.Imaging.BitmapTransform(), Windows.Graphics.Imaging.ExifOrientationMode.RespectExifOrientation, Windows.Graphics.Imaging.ColorManagementMode.ColorManageToSRgb);
var pixels = pixelProvider.DetachPixelData();
var width = decoder.OrientedPixelWidth;
var height = decoder.OrientedPixelHeight;
Parallel.For(0, height, i =>
{
for (int j = 0; j <= width - 1; j++)
{
// Alpha channel Index (RGBA)
var idx = (i * height + j) * 4 + 3;
}
});
var randomAccessStream = new InMemoryRandomAccessStream();
var outputStream = randomAccessStream.GetOutputStreamAt(0);
var writer = new DataWriter(outputStream);
writer.WriteBytes(pixels);
await writer.StoreAsync();
await writer.FlushAsync();
args.Request.PixelData = RandomAccessStreamReference.CreateFromStream(randomAccessStream);
}
}
catch
{
}
deferral.Complete();
}
private Task<MemoryStream> GetTileAsStreamAsync(int x, int y, int zoom)
{
var tcs = new TaskCompletionSource<MemoryStream>();
var quadkey = TileXYZoomToQuadKey(x, y, zoom);
string url;
url = _tileUrl.Replace("{x}", x.ToString()).Replace("{y}", y.ToString()).Replace("{zoomlevel}", zoom.ToString()).Replace("{quadkey}", quadkey);
var request = WebRequest.Create(url);
foreach (var defaultHeader in DefaultRequestHeaders)
{
request.Headers.Add(defaultHeader.Key, defaultHeader.Value);
}
if (AdditionalRequestHeaders.Count > 0)
{
foreach (var addHeader in AdditionalRequestHeaders)
{
request.Headers.Add(addHeader.Key, addHeader.Value);
}
}
request.BeginGetResponse(async a =>
{
var r = (HttpWebRequest)a.AsyncState;
HttpWebResponse response = (HttpWebResponse)r.EndGetResponse(a);
using (var s = response.GetResponseStream())
{
var ms = new MemoryStream();
await s.CopyToAsync(ms);
ms.Position = 0;
tcs.SetResult(ms);
}
}, request);
return tcs.Task;
}
private string TileXYZoomToQuadKey(int tileX, int tileY, int zoom)
{
var quadKey = new StringBuilder();
for (int i = zoom; i >= 1; i += -1)
{
char digit = '0';
int mask = 1 << (i - 1);
if ((tileX & mask) != 0)
Strings.ChrW(Strings.AscW(digit) + 1);
if ((tileY & mask) != 0)
{
Strings.ChrW(Strings.AscW(digit) + 1);
Strings.ChrW(Strings.AscW(digit) + 1);
}
quadKey.Append(digit);
}
return quadKey.ToString();
}
}
Usage
var dataSource = new CustomTileDataSource("https://tile.openstreetmap.org/{zoomlevel}/{x}/{y}.png");
dataSource.AdditionalRequestHeaders.Add("header_name", "header_value");
// other code
var mySource = new MapTileSource(dataSource);
myMap.TileSources.Add(mySource);
During the test, I also encountered the problem that HttpMapTileDataSource.AdditionalRequestHeaders does not display. I tried to use CustomMapTileDataSource to derive and rewrite the related methods so that it can work normally.
The reason for saying that it is a semi-finished product is that it does not establish a good caching mechanism, and the initial loading time is very long.
Best regards.

Combine the multiple API responses in to one JSON object C#

I am calling the Sharepoint REST API from the C# application multiple times becaues of pagination and it cannot return more the 5000 records at a time. I am calling the API through the loop like
for (int i = 0; i < 10000; i = i + 5000)
{
SP_StrainCodes = "GetByTitle('S%20Codes')/items?$skiptoken=Paged=TRUE%26p_ID=" + i + "&$top=1";
core_URL = BaseURL_SP + SP_StrainCodes;
using (var client_sharePoint = new HttpClient(handler))
{
var response = client_sharePoint.GetAsync(core_URL).Result;
var responsedata = await response.Content.ReadAsStringAsync();
returnObj = JsonConvert.DeserializeObject<SharepointDTO.RootObject>(responsedata);
if (returnObj.d.Next == null)
continue;
}
}
return returnObj;
}
How do I combine the the returnObj from 1st call and the 2nd Call and return as one Object
Something like this :
List<SharepointDTO.RootObject> results = new List<SharepointDTO.RootObject>();
for (int i = 0; i < 10000; i = i + 5000)
{
SP_StrainCodes = "GetByTitle('S%20Codes')/items?$skiptoken=Paged=TRUE%26p_ID=" + i + "&$top=1";
core_URL = BaseURL_SP + SP_StrainCodes;
using (var client_sharePoint = new HttpClient(handler))
{
var response = client_sharePoint.GetAsync(core_URL).Result;
var responsedata = await response.Content.ReadAsStringAsync();
returnObj = JsonConvert.DeserializeObject<SharepointDTO.RootObject>(responsedata);
if (returnObj.d.Next == null)
continue;
}
results.Add(returnObj);
}
return results;

request.getResponse() is getting error

This is my code which is returning the expected output on my friend's PC, but not on mine.
We are both working with Visual Studio 2017 Community:
enter image description here
This is the code that will return latitude and longitude of the entered address:
[enter image description here][2]
The first time it works fine but after that its throwing (403 forbidden error !!! / mainly problem is on the request.getResponse())
private static String[] x = new String[3];
public static String[] GetFirstLastName(string address)
{
try {
string url = "http://maps.google.com/maps/api/geocode/xml?address=" + address + "&sensor=false";
WebRequest request = WebRequest.Create(url);
// request.UseDefaultCredentials = true;
// request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
// request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
using (WebResponse response = (HttpWebResponse)request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
var ds = new DataSet("Employee");
ds.ReadXml(reader);
DataRow dr = null;
var dt = new DataTable("Employee");
dt.Columns.AddRange(new DataColumn[2]
{
new DataColumn("Latitude", typeof (string)),
new DataColumn("Longitude", typeof (string))
});
int i = 0;
try
{
foreach (DataRow row in ds.Tables["result"].Rows)
{
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return x;
}
foreach (DataRow row in ds.Tables["result"].Rows)
{
if (i == 0)
{
string geometry_id = ds.Tables["geometry"].Select("result_id = " + row["result_id"])[0]["geometry_id"].ToString();
dr = ds.Tables["location"].Select("geometry_id = " + geometry_id)[0];
dt.Rows.Add(dr["lat"], dr["lng"]);
// Console.WriteLine(dr["lat"].ToString() + " " + dr["lng"].ToString());
i = 1;
break;
}
}
x[0] = dr["lat"].ToString();
x[1] = dr["lng"].ToString();
reader.Close();
}
// request.Timeout = 0;
// request.Abort();
response.Close();
return x;
}
}
catch(Exception e)
{
Console.WriteLine(e);
x[0] = "";
x[1] = "";
return x;
}
}
public static String[] GetFirstLastName1(string address)
{
try
{
string url = "http://maps.google.com/maps/api/geocode/xml?address=" + address + "&sensor=false";
WebRequest request = WebRequest.Create(url);
// request.UseDefaultCredentials = true;
// request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
// request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
using (WebResponse response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
var ds = new DataSet("Employee");
ds.ReadXml(reader);
DataRow dr = null;
var dt = new DataTable("Employee");
dt.Columns.AddRange(new DataColumn[2]
{
new DataColumn("Latitude", typeof (string)),
new DataColumn("Longitude", typeof (string))
});
int i = 0;
try
{
foreach (DataRow row in ds.Tables["result"].Rows)
{
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return x;
}
foreach (DataRow row in ds.Tables["result"].Rows)
{
if (i == 0)
{
string geometry_id = ds.Tables["geometry"].Select("result_id = " + row["result_id"])[0]["geometry_id"].ToString();
dr = ds.Tables["location"].Select("geometry_id = " + geometry_id)[0];
dt.Rows.Add(dr["lat"], dr["lng"]);
// Console.WriteLine(dr["lat"].ToString() + " " + dr["lng"].ToString());
i = 1;
break;
}
}
x[0] = dr["lat"].ToString();
x[1] = dr["lng"].ToString();
reader.Close();
}
//// request.Timeout = 0;
/// request.Abort();
response.Close();
return x;
}
}
catch (Exception e)
{
Console.WriteLine(e);
x[0] = "";
x[1] = "";
return x;
}
}
static void Main(string[] args)
{
int i = 0;
for (;;)
{
String x = Console.ReadLine();
if (i == 0)
{
String[] y = GetFirstLastName(x);
Console.WriteLine(y[0] + " " + y[1]);
}
else
{
String[] y = GetFirstLastName1(x);
Console.WriteLine(y[0] + " " + y[1]);
}
i++;
}
//Console.ReadKey();
}
}
}
/*(Same Code above)
enter code here
///My Friends Output
/// My Output
[2]: https://i.stack.imgur.com/qeDcz.png */
Glad to see you've joined StackOverflow!
Now a 403 error occurs usually not in relation to a syntax error in your code but in relation to the response received from Google's servers.
Now Google in particular is very restrictive on how many API calls you can make a day (Google makes a lot of money off developers who pay for lots of API calls). This page contains the limits. If you've made more than the numbers in here, that's why you're getting the error and you'll have to wait until tomorrow. Do keep in mind not to send too many http requests and accidentally DOS them, as they'll blacklist you for this.
Make sure you are not caching their page or storing the js script locally as this will also cause a blacklist.
Make sure you use https: and not http: here.

Facebook Real-time Update: Validating X-Hub-Signature SHA1 signature in C#

When Facebook sends real-time updates, they include a X-Hub-Signature in the HTTP header. According to their documentation (http://developers.facebook.com/docs/api/realtime), they're using SHA1 and the application secret as the key. I tried to verify the signature like this:
public void MyAction() {
string signature = request.Headers["X-Hub-Signature"];
request.InputStream.Position = 0;
StreamReader reader = new StreamReader(request.InputStream);
string json = reader.ReadToEnd();
var hmac = SignWithHmac(UTF8Encoding.UTF8.GetBytes(json), UTF8Encoding.UTF8.GetBytes("MySecret"));
var hmacBase64 = ToUrlBase64String(hmac);
bool isValid = signature.Split('=')[1] == hmacBase64;
}
private static byte[] SignWithHmac(byte[] dataToSign, byte[] keyBody) {
using (var hmacAlgorithm = new System.Security.Cryptography.HMACSHA1(keyBody)) {
hmacAlgorithm.ComputeHash(dataToSign);
return hmacAlgorithm.Hash;
}
}
private static string ToUrlBase64String(byte[] Input) {
return Convert.ToBase64String(Input).Replace("=", String.Empty)
.Replace('+', '-')
.Replace('/', '_');
}
But I can't seem to get this to ever validate. Any thoughts on what I'm doing wrong?
Thanks in advance.
In case someone will need this information:
What Kelvin offered might work, but it seems very cumbersome.
All you need is instead of using the ToUrlBase64String function just use the ConvertToHexadecimal function.
See fully updated code below:
public void MyAction() {
string signature = request.Headers["X-Hub-Signature"];
request.InputStream.Position = 0;
StreamReader reader = new StreamReader(request.InputStream);
string json = reader.ReadToEnd();
var hmac = SignWithHmac(UTF8Encoding.UTF8.GetBytes(json), UTF8Encoding.UTF8.GetBytes("MySecret"));
var hmacHex = ConvertToHexadecimal(hmac);
bool isValid = signature.Split('=')[1] == hmacHex ;
}
private static byte[] SignWithHmac(byte[] dataToSign, byte[] keyBody) {
using (var hmacAlgorithm = new System.Security.Cryptography.HMACSHA1(keyBody)) {
return hmacAlgorithm.ComputeHash(dataToSign);
}
}
private static string ConvertToHexadecimal(IEnumerable<byte> bytes)
{
var builder = new StringBuilder();
foreach (var b in bytes)
{
builder.Append(b.ToString("x2"));
}
return builder.ToString();
}
The code below will resolve the problem for you:
public String hmacSha1(String keyString, byte[] in) throws GeneralSecurityException {
Mac hmac = Mac.getInstance("HmacSHA1");
int keySize = keyString.length();
byte[] keyBytes = new byte[keySize];
for (int i = 0; i < keyString.length(); i++) {
keyBytes[i] = (byte) keyString.charAt(i);
}
Key key = new SecretKeySpec(keyBytes, "HmacSHA1");
hmac.init(key);
hmac.update(in);
byte[] bb = hmac.doFinal();
StringBuilder v = new StringBuilder();
for (int i = 0; i < bb.length; i++) {
int ch = bb[i];
int d1 = (ch >> 4) & 0xf;
int d2 = (ch) & 0xf;
if (d1 < 10) {
v.append((char) ('0' + d1));
} else {
v.append((char) ('a' + d1 - 10));
}
if (d2 < 10) {
v.append((char) ('0' + d2));
} else {
v.append((char) ('a' + d2 - 10));
}
}
return v.toString();
}
public String callback(HttpServletRequest request) throws IOException {
InputStream in = request.getInputStream();
StringBuilder builder = new StringBuilder();
byte[] buffer = new byte[1024];
while (in.read(buffer) > 0) {
builder.append(new String(buffer));
}
String signature = request.getHeader("X-Hub-Signature");
try {
String signed = subscriptionService.hmacSha1("YOUR_SECRET", builder.toString().getBytes());
if (signature.startsWith("sha1=") && signature.substring(4).equals(signed)) {
// process the update
....
}
} catch (GeneralSecurityException ex) {
log.warn(ex.getMessage());
}
return null;
}

Categories