This is my api
[HttpPost]
[Route("uploadfile")]
public HttpResponseMessage PostFile(HttpRequest request)
{
HttpResponseMessage result = null;
var httpRequest = request;//HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("Uploads/" + postedFile.FileName);
postedFile.SaveAs(filePath);
docfiles.Add(filePath);
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
This is my client code
private async void button_Click(object sender, RoutedEventArgs e)
{
byte[] a = File.ReadAllBytes(#"C:\My folder\MyFile.txt");
FileStream stream = File.Open(#"C:\My folder\MyFile.txt", FileMode.Open);
Upload(#"http://localhost:56885/uploadfile", "MyFile", stream, a);
MessageBox.Show("File uploaded Successfully");
}
private Stream Upload(string url, string param1,
Stream fileStream, byte[] fileBytes)
{
HttpContent stringContent = new StringContent(param1);
HttpContent fileStreamContent = new StreamContent(fileStream);
HttpContent bytesContent = new ByteArrayContent(fileBytes);
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(stringContent, "param1", "param1");
formData.Add(fileStreamContent, "file1", "file1");
formData.Add(bytesContent, "file2", "file2");
var response = client.PostAsync(url, formData).Result;
if (!response.IsSuccessStatusCode)
{
return null;
}
MessageBox.Show("File uploaded Successfully");
return response.Content.ReadAsStreamAsync().Result;
}
}
I was getting an error {
"message": "The request entity's media type 'multipart/form-data' is not supported for this resource.",
"exceptionMessage": "No MediaTypeFormatter is available to read an object of type 'HttpRequest' from content with media type 'multipart/form-data'.",
"exceptionType": "System.Net.Http.UnsupportedMediaTypeException",
"stackTrace": " at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken) at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken) at System.Web.Http.ModelBinding.FormatterParameterBinding.ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger, CancellationToken cancellationToken)"
}
Related
I'm using HttpMessageHandler to log Http Request and Response. If internet connection is not available I get HttpRequestException, but this Exception is not catched (try catch not working). If I don't use HttpMessageHandler Exception is catched.
Method with try catch :
public JObject Get()
{
string url = "/...";
try
{
using (var httpClientHandler = new HttpClientHandler())
{
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert,
chain, errors) =>
{ return true; };
using (var client = new HttpClient(new LoggingHandler(httpClientHandler)))
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue(CONTENT_TYPE_JSON));
var byteArray = Encoding.ASCII.GetBytes("");
client.DefaultRequestHeaders.Authorization = new
System.Net.Http.Headers.AuthenticationHeaderValue("Basic",
Convert.ToBase64String(byteArray));
HttpResponseMessage response = client.GetAsync(url).Result;
response.EnsureSuccessStatusCode();
var json = response.Content.ReadAsStringAsync().Result;
JObject rss = JObject.Parse(json);
return rss;
}
}
}
catch(HttpRequestException ex)
{
//Catch not working
return null;
}
}
HttpMessageHandler :
public class LoggingHandler : DelegatingHandler
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(LoggingHandler));
public LoggingHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage response = null;
Loging("Request:");
Loging(request.ToString());
if (request.Content != null)
{
Loging(await request.Content.ReadAsStringAsync());
}
Loging("");
response = await base.SendAsync(request, cancellationToken);
Loging("Response:");
Loging(response.ToString());
if (response.Content != null)
{
Loging(await response.Content.ReadAsStringAsync());
}
Loging("");
return response;
}
private void Loging(string message)
{
Debug.WriteLine(message);
log.Info(message);
}
}
Why is it happining?
// ASP.NET Identity
serviceRegistry.For<IPasswordHasher<User>>().Add<CustomPasswordHasher>();
serviceRegistry.For<CustomDbContext>()
.Use(s => new DesignTimeDbContextFactory().CreateDbContext(Array.Empty<string>()))
.Scoped();
serviceRegistry.AddTransient<IUserStore<User>, CustomUserStore>();
serviceRegistry.AddTransient<IUserClaimStore<User>, CustomUserStore>();
serviceRegistry.AddIdentityCore<User>();
serviceRegistry.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
}).AddIdentityCookies();
I then sign in using the following in my controller action...
var result = await mSignInManager.PasswordSignInAsync(user.Username, model.Password, false, false );
.. and I see UserClaimsPrincipalFactory.GenerateClaimsAsync calling my custom claims store and receiving the expected list of claims.
I have set a break point just beyond the PasswordSignInAsync call but when I look at the User property on the controller there are no claims on there.
Would seem either my config is up the creek, I am missing some code or the order of what I am doing is incorrect or all of the previous! :-(
(All code is work in progress and by no means production ready!)
EDIT:
// I am using Lamar so this is the same as Startup.ConfigureContainer
public static void Configure(ServiceRegistry serviceRegistry, IConfiguration configuration)
{
var clients = ClientHelper.GetClients(configuration);
var tenants = new TenantFactory().CreateTenants(clients);
serviceRegistry.AddHttpContextAccessor();
serviceRegistry.ConfigureOptions<ConfigureMvcOptions>();
serviceRegistry.ConfigureOptions<ConfigureMvcViewOptions>();
serviceRegistry.ConfigureOptions<ConfigureRazorViewOptions>();
serviceRegistry.ConfigureOptions<ConfigureSessionOptions>();
serviceRegistry.ConfigureOptions<ConfigureAntiforgeryOptions>();
serviceRegistry.AddDistributedMemoryCache();
serviceRegistry.AddSession();
serviceRegistry.AddMvc()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
serviceRegistry.AddAntiforgery(opts => opts.FormFieldName = "__RequestVerificationToken");
serviceRegistry.AddRouteAnalyzer();
// ASP.NET Identity
serviceRegistry.For<CustomDbContext>()
.Use(s => new DesignTimeDbContextFactory().CreateDbContext(Array.Empty<string>()))
.Scoped();
serviceRegistry.For<IPasswordHasher<User>>().Add<AtsPasswordHasher>();
serviceRegistry.AddTransient<IUserStore<User>, CustomUserStore>();
serviceRegistry.AddTransient<IUserClaimStore<User>, CustomUserStore>();
serviceRegistry.AddIdentityCore<User>()
.AddSignInManager()
.AddDefaultTokenProviders();
serviceRegistry.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
}).AddIdentityCookies(o => { });
}
Edit 2:
Controller Action - result.Succeeded is true
[AllowAnonymous]
[HttpPost]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Logon(LogonViewModel model)
{
if (ModelState.IsValid)
{
var user = await mUserManager.FindByNameAsync(model.Username);
var result = await mSignInManager.PasswordSignInAsync(user.Username, model.Password, false, false );
if (result.Succeeded)
{
mLogger.LogInformation(1, "User logged in.");
try
{
var sessionState = CreateSessionState(user.Username, mUserStateManager.ClientIpAddress);
var sessionData = CreateSessionData(sessionState, user);
mSessionWrapper.Session = sessionData;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return RedirectToAction("SessionCreated",
new
{
returnUrl = string.IsNullOrEmpty(model.ReturnUrl)
? Request.Query["ReturnUrl"].ToString()
: model.ReturnUrl,
username = model.Username,
currentpassword = model.ResetToken
});
//return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
//return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
mLogger.LogWarning(2, "User account locked out.");
//return View("Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
// Default to returning the original view once more
return View("Logon", model);
}
User Store and Claims Store - FindByNameAsync and GetClaimsAsync work
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Core.Auth.Model;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace Core.Auth.Identity.EFCore
{
public class CustomUserStore : IUserStore<User>, IUserClaimStore<User>, IUserPasswordStore<User>
{
private bool mDisposed;
private CustomUserStore() { }
public CustomUserStore(CustomDbContext context)
{
Context = context ?? throw new ArgumentNullException(nameof(context));
}
public virtual CustomDbContext Context { get; private set; }
private DbSet<User> Users => Context.Set<User>();
#region IUserStore<User> implementation
public void Dispose()
{
mDisposed = true;
}
public async Task<string> GetUserIdAsync(User user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
var foundUser = await FindUserById(user, cancellationToken);
return foundUser?.UserId.ToString();
}
public async Task<string> GetUserNameAsync(User user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
var foundUser = await FindUserById(user, cancellationToken);
return foundUser?.Username;
}
public Task SetUserNameAsync(User user, string userName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetNormalizedUserNameAsync(User user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetNormalizedUserNameAsync(User user, string normalizedName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IdentityResult> CreateAsync(User user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IdentityResult> UpdateAsync(User user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IdentityResult> DeleteAsync(User user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public async Task<User> FindByIdAsync(string userId, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
return await Users.FirstOrDefaultAsync(x => x.UserId.ToString() == userId, cancellationToken: cancellationToken);
}
public Task<User> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
return Users.FirstOrDefaultAsync(u => u.Username == normalizedUserName, cancellationToken);
}
#endregion
#region IUserClaimStore<User> implementation
public async Task<IList<Claim>> GetClaimsAsync(User user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
// Data model is a little "odd" so having to this in a mechanical fashion for now
var securityRoleIdsForUser = await Context
.UserToSecurityRoles
.Where(x => x.UserId == user.UserId)
.Select(x => x.SecurityRoleId)
.ToArrayAsync( cancellationToken);
var securityRoles = await Context
.SecurityRoles
.Where(x => securityRoleIdsForUser.Contains(x.SecurityRoleId))
.Select(x => x.SecurityRoleName)
.ToArrayAsync(cancellationToken);
var claims = securityRoles.Select(securityRole => new Claim(ClaimTypes.Role, securityRole)).ToList();
return claims;
}
public Task AddClaimsAsync(User user, IEnumerable<Claim> claims, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task ReplaceClaimAsync(User user, Claim claim, Claim newClaim, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task RemoveClaimsAsync(User user, IEnumerable<Claim> claims, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<IList<User>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
#endregion
#region IUserPasswordStore<User> implementation
public Task SetPasswordHashAsync(User user, string passwordHash, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public async Task<string> GetPasswordHashAsync(User user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
var foundUser = await FindUserById(user, cancellationToken);
return foundUser.Rfc2898PasswordHash;
}
public Task<bool> HasPasswordAsync(User user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
#endregion
/// <summary>
/// Throws if this class has been disposed.
/// </summary>
protected void ThrowIfDisposed()
{
if (mDisposed)
{
throw new ObjectDisposedException(GetType().Name);
}
}
private async Task<User> FindUserById(User user, CancellationToken cancellationToken)
{
var foundUser = await Users.FirstOrDefaultAsync(x => x.UserId == user.UserId, cancellationToken: cancellationToken);
return foundUser;
}
}
}
Please see the code below. Using in-memory hosting of httpclient, and Passing httpclient object to controller in order to unit test action method. But I am getting "Internal Server Error" ReasonPhrase upon HttpResponseMessage response =_httpClient.GetAsync. Please help me, is it correct approach?
private readonly HttpClient _httpClient;
public SecurityMfMvcController(HttpClient httpClient)
{
this._httpClient = httpClient;
}
[HttpGet]
public ActionResult GetSecuritiesMfs()
{
try
{
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response =
_httpClient.GetAsync(ConfigurationManager.AppSettings["ApiUrl"] + "SecuritiesWebApiMf").Result;
response.EnsureSuccessStatusCode();
List<SecurityMutualFundDto> list =
response.Content.ReadAsAsync<List<SecurityMutualFundDto>>().Result;
return View("SecuritiesMf", list);
}
catch (Exception ex)
{
return View("Error", ex.Message);
}
}
//Unit Test Method for this Action
[Test]
public void TestActionGetSecuritiesMfs()
{
var config = new HttpConfiguration()
{
IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always
};
//use the configuration that the web application has defined
WebApiConfig.Register(config);
HttpServer server = new HttpServer(config);
//create a client with a handler which makes sure to exercise the formatters
using (var client = new HttpClient(new InMemoryHttpContentSerializationHandler(server)))
{
System.Uri uri = new System.Uri("http://localhost:55893/api/");
client.BaseAddress = uri;
var controller = new SecurityMfMvcController(client);
var result = controller.GetSecuritiesMfs();
Assert.IsNotNull(result);
}
}
//MessageHandler
public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Content = await ConvertToStreamContentAsync(request.Content);
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Content = await ConvertToStreamContentAsync(response.Content);
return response;
}
private async Task<StreamContent> ConvertToStreamContentAsync(HttpContent originalContent)
{
if (originalContent == null)
{
return null;
}
StreamContent streamContent = originalContent as StreamContent;
if (streamContent != null)
{
return streamContent;
}
MemoryStream ms = new MemoryStream();
await originalContent.CopyToAsync(ms);
// Reset the stream position back to 0 as in the previous CopyToAsync() call,
// a formatter for example, could have made the position to be at the end
ms.Position = 0;
streamContent = new StreamContent(ms);
// copy headers from the original content
foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
{
streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
return streamContent;
}
}
You could mock your http request pipeline and test your action:
var mockHttpRequest = new Mock<HttpRequestMessage>(new object[] {new HttpMethod("GET"), "www.someuri.com"});
var mockHttpConfig = new Mock<HttpConfiguration>();
var mockRouteData = new Mock<IHttpRouteData>();
var mockHttpContext =
new Mock<HttpControllerContext>(new object[]
{mockHttpConfig.Object, mockRouteData.Object, mockHttpRequest.Object});
Then set your controller object with these values:
var controller = new YourController();
controller.ControllerContext = mockHttpContext.Object;
controller.Request = controller.ControllerContext.Request;
response = controller.SecuritiesMF();
and you could check your response as follows:
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
I got it working, correct me in case of anything wrong here. I have to create a "FakeHttpMessageHandler" as below and the content type to match System.Net.Http.StreamContent for application/json content type. the below code is working to unit test mvc action method using httpclient to call WebAPI. however I need to double check whether this is the right approach for unit test, will review further.
[Test]
public void TestActionMethodSelectByIdUsingFakeHandler()
{
var uobj = new UnitTestForApiController();
var testobj= uobj.GetsecuritiesMfsList();
MemoryStream stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, testobj);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{Content = new StreamContent(stream)};
using (var httpClient = new HttpClient(new FakeHandler
{
Response = response,
InnerHandler = new HttpClientHandler()
}))
{
System.Uri uri = new System.Uri("http://localhost:55893/api/");
httpClient.BaseAddress = uri;
var controller = new SecuritiesMfMvcController(httpClient);
var result = controller.Select(2155) as ViewResult;
Assert.IsNotNull(result);
Assert.AreEqual(result.ViewName,"Select");
Assert.AreEqual(result.Model, testobj.FirstOrDefault());
}
//FakeHandler class goes as below
public class FakeHandler : DelegatingHandler
{
public HttpResponseMessage Response { get; set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
return Task.Factory.StartNew(() => Response, cancellationToken);
}
}
//We can also have logic for abstracting appropriate StreamContent Creation into FakeContent class like below:
public class FakeHttpContent : HttpContent
{
public object Content { get; set; }
public FakeHttpContent(object content)
{
Content = content;
}
protected async override Task SerializeToStreamAsync(Stream stream,
TransportContext context)
{
MemoryStream ms = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, Content);
await ms.CopyToAsync(stream);
}
protected override bool TryComputeLength(out long length)
{
length = Content.ToString().Length;
return true;
}
}
I am using a custom Media formatter to read post data for multipartform in webapi. Handling the serialization errors and validation errors in a custom Action Filter Attribute. In the formatter I am mapping the input to a Type Object ImageMedia. I want to add any serliazation errors to the ModelState so that I can handle the those in the CustomFilterAttribute, which recieve an ActionContext. Here is the code:
public class ImageMediaFormatter : MediaTypeFormatter
{
public ImageMediaFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpeg"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpg"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/png"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/gif"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data"));
}
public override bool CanReadType(Type type)
{
return type == typeof(ImageMedia);
}
public override bool CanWriteType(Type type)
{
return false;
}
public override Task<object> ReadFromStreamAsync(
Type type, Stream stream, HttpContent request,
IFormatterLogger formatterContext)
{
return Task.Factory.StartNew<object>(() =>
{
var streamProvider = new MultipartMemoryStreamProvider();
var keys = new Dictionary<string, string>();
var result = request.ReadAsMultipartAsync(streamProvider).Result;
//get and remove random slashes from posted vaues
var categoryid =
streamProvider.Contents.First(x => x.Headers.ContentDisposition.Name.Contains("userGeneratedCategoryId")).ReadAsStringAsync().Result.Replace("\"", string.Empty);
keys.Add(Constants.UserGeneratedCategoryId, categoryid);
var imageBuffer =
streamProvider.Contents.First(x => x.Headers.ContentDisposition.Name.Contains(Constants.ImageFile)).ReadAsByteArrayAsync().Result;
return new ImageMedia(keys, imageBuffer);
});
}
}
public class ImageMedia
{
public ImageMedia(Dictionary<string, string> keys, byte[] imageBuffer)
: this()
{
var keyvaluePair = new KeyValuePair<string, string>();
foreach (var property in GetType().GetProperties())
{
try
{
keyvaluePair = keys.FirstOrDefault(pair => pair.Key.ToLower() == property.Name.ToLower());
if (!string.IsNullOrEmpty(keyvaluePair.Key))
{
property.SetValue(this, keyValuePair.Value, null);
}
}
catch (Exception ex)
{
// Add these serialization errors to the Model State so I can handle these in a Custom Validation Action Attribute
Errors.Add(keyvaluePair.Key, new List<string> { ex.Message });
IsValid = false;
}
}
Buffer = imageBuffer;
}
private ImageMedia()
{
Errors = new Dictionary<string, List<string>>();
}
public int UserGeneratedCategoryId { get; set; }
public byte[] Buffer { get;set;}
}
You could added errors to the supplied IFormatterLogger context that is passed in to ReadFromStreamAsync method:
public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContent request,
IFormatterLogger formatterContext)
Example:
formatterLogger.LogError(errorPath: "OrderedDate", errorMessage: "Not a valid date");
I always get the 404 error.Below is my complete code for sending the push notification of type Toast from the wcf service.Anything wrong with the message ?
string channelURI = "http://db3.notify.live.net/throttledthirdparty/01.00/AgAAAAQUZm52OjBEMTRBNDEzQjc4RUFBRTY";
HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(channelURI);
//Indicate that you'll send toast notifications!
sendNotificationRequest.ContentType = "text/xml";
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast");
sendNotificationRequest.Headers.Add("X-NotificationClass", "2");
sendNotificationRequest.Method = "POST";
sendNotificationRequest.Headers.Add("X-MessageID",Guid.NewGuid().ToString());
if (string.IsNullOrEmpty(message)) return "empty cannot be sent";
//send it
var msg = string.Format("sample toast message", "Toast Message", "This is from server");
byte[] notificationMessage = Encoding.UTF8.GetBytes(msg);
sendNotificationRequest.ContentLength = notificationMessage.Length;
//Push data to stream
using (Stream requestStream = sendNotificationRequest.GetRequestStream())
{
requestStream.Write(notificationMessage, 0, notificationMessage.Length);
}
//Get reponse for message sending
HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
string notificationStatus = response.Headers["X-NotificationStatus"];
string notificationChannelStatus = response.Headers["X-SubscriptionStatus"];
string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];
return notificationStatus;
this code may help you
private static byte[] prepareToastPayload(string text1, string text2)
{
MemoryStream stream = new MemoryStream();
XmlWriterSettings settings = new XmlWriterSettings() { Indent = true, Encoding = Encoding.UTF8 };
XmlWriter writer = XmlTextWriter.Create(stream, settings);
writer.WriteStartDocument();
writer.WriteStartElement("wp", "Notification", "WPNotification");
writer.WriteStartElement("wp", "Toast", "WPNotification");
writer.WriteStartElement("wp", "Text1", "WPNotification");
writer.WriteValue(text1);
writer.WriteEndElement();
writer.WriteStartElement("wp", "Text2", "WPNotification");
writer.WriteValue(text2);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
byte[] payload = stream.ToArray();
return payload;
}
private void SendMessage(Uri channelUri, byte[] payload, NotificationType notificationType, SendNotificationToMPNSCompleted callback)
{
//Check the length of the payload and reject it if too long
if (payload.Length > MAX_PAYLOAD_LENGTH)
throw new ArgumentOutOfRangeException(
"Payload is too long. Maximum payload size shouldn't exceed " + MAX_PAYLOAD_LENGTH.ToString() + " bytes");
try
{
//Create and initialize the request object
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(channelUri);
request.Method = WebRequestMethods.Http.Post;
request.ContentType = "text/xml; charset=utf-8";
request.ContentLength = payload.Length;
request.Headers[MESSAGE_ID_HEADER] = Guid.NewGuid().ToString();
request.Headers[NOTIFICATION_CLASS_HEADER] = ((int)notificationType).ToString();
if (notificationType == NotificationType.Toast)
request.Headers[WINDOWSPHONE_TARGET_HEADER] = "toast";
else if (notificationType == NotificationType.Token)
request.Headers[WINDOWSPHONE_TARGET_HEADER] = "token";
request.BeginGetRequestStream((ar) =>
{
//Once async call returns get the Stream object
Stream requestStream = request.EndGetRequestStream(ar);
//and start to write the payload to the stream asynchronously
requestStream.BeginWrite(payload, 0, payload.Length, (iar) =>
{
//When the writing is done, close the stream
requestStream.EndWrite(iar);
requestStream.Close();
//and switch to receiving the response from MPNS
request.BeginGetResponse((iarr) =>
{
using (WebResponse response = request.EndGetResponse(iarr))
{
//Notify the caller with the MPNS results
OnNotified(notificationType, (HttpWebResponse)response, callback);
}
},
null);
},
null);
},
null);
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
//Notify client on exception
OnNotified(notificationType, (HttpWebResponse)ex.Response, callback);
}
throw;
}
}
protected void OnNotified(NotificationType notificationType, HttpWebResponse response, SendNotificationToMPNSCompleted callback)
{
CallbackArgs args = new CallbackArgs(notificationType, response);
if (null != callback)
callback(args);
}
public class CallbackArgs
{
public CallbackArgs(NotificationType notificationType, HttpWebResponse response)
{
this.Timestamp = DateTimeOffset.Now;
this.MessageId = response.Headers[NotificationSenderUtility.MESSAGE_ID_HEADER];
this.ChannelUri = response.ResponseUri.ToString();
this.NotificationType = notificationType;
this.StatusCode = response.StatusCode;
this.NotificationStatus = response.Headers[NotificationSenderUtility.NOTIFICATION_STATUS_HEADER];
this.DeviceConnectionStatus = response.Headers[NotificationSenderUtility.DEVICE_CONNECTION_STATUS_HEADER];
this.SubscriptionStatus = response.Headers[NotificationSenderUtility.SUBSCRIPTION_STATUS_HEADER];
}
public DateTimeOffset Timestamp { get; private set; }
public string MessageId { get; private set; }
public string ChannelUri { get; private set; }
public NotificationType NotificationType { get; private set; }
public HttpStatusCode StatusCode { get; private set; }
public string NotificationStatus { get; private set; }
public string DeviceConnectionStatus { get; private set; }
public string SubscriptionStatus { get; private set; }
}
public enum NotificationType
{
Token = 1,
Toast = 2,
Raw = 3
}