Just started using ASP.Net 4.5 and my API always returns Internal Server Error.
Upload API
public class UploadController : ApiController
{
public async Task<HttpResponseMessage> PostFile()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data/uploads/");
var provider = new CustomMultipartFormDataStreamProvider(root);
try
{
await Request.Content.ReadAsMultipartAsync(provider);
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
My Controller
var message = new HttpRequestMessage();
var content = new MultipartFormDataContent();
message.Method = HttpMethod.Post;
message.Content = content;
message.RequestUri = new Uri("http://localhost:12345/api/upload/");
var client = new HttpClient();
client.SendAsync(message).ContinueWith(task =>
{
var result = task.Result.ReasonPhrase;
if (task.Result.IsSuccessStatusCode)
{
//do something
}
});
The files are saved in the location (/App_Data/uploads/) but why is the status code always 500?
Please enlighten me. Thanks
Here is part of working controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(Product product, HttpPostedFileBase file)
{
if (!ModelState.IsValid)
return PartialView("Create", product);
if (file != null)
{
var fileName = Path.GetFileName(file.FileName);
var guid = Guid.NewGuid().ToString();
var path = Path.Combine(Server.MapPath("~/Content/Uploads/ProductImages"), guid + fileName);
file.SaveAs(path);
string fl = path.Substring(path.LastIndexOf("\\"));
string[] split = fl.Split('\\');
string newpath = split[1];
string imagepath = "Content/Uploads/ProductImages/" + newpath;
using (MemoryStream ms = new MemoryStream())
{
file.InputStream.CopyTo(ms);
byte[] array = ms.GetBuffer();
}
var nId = Guid.NewGuid().ToString();
// Save record to database
product.Id = nId;
product.State = 1;
product.ImagePath = imagepath;
product.CreatedAt = DateTime.Now;
db.Products.Add(product);
await db.SaveChangesAsync();
TempData["message"] = "ProductCreated";
//return RedirectToAction("Index", product);
}
// after successfully uploading redirect the user
return Json(new { success = true });
}
Related
I use seed to enter default data into the database, but I am facing a problem, which is the FK,
How do I pass the value of FK to the two tables without any problem ?
I get this error when I run the program :
SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_AspNetUsers_Departments_DepartmentId". The conflict occurred in database "HRS.WEB1", table "dbo.Departments", column 'Id'.
The statement has been terminated.
public static class DbSeeder
{
public static IHost SeedDb(this IHost webHost)
{
using var scope = webHost.Services.CreateScope();
try
{
var context = scope.ServiceProvider.GetRequiredService<HRSDbContext>();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<Employee>>();
context.SeedDepartment().Wait();
userManager.SeedEmployee().Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
return webHost;
}
public static async Task SeedDepartment(this HRSDbContext _db)
{
if (await _db.Departments.AnyAsync())
{
return;
}
var departments = new List<Department>();
var department = new Department();
department.Name = "A1";
department.Id = 1;
department.CreatedAt = DateTime.Now;
var department2 = new Department();
department2.Name = "A2";
department2.Id = 2;
department2.CreatedAt = DateTime.Now;
departments.Add(department);
departments.Add(department2);
await _db.Departments.AddRangeAsync(departments);
await _db.SaveChangesAsync();
}
public static async Task SeedEmployee(this UserManager<Employee> userManger)
{
if (await userManger.Users.AnyAsync())
{
return;
}
var user = new Employee();
user.FullName = "System Developer";
user.UserName = "dev#gmail.com";
user.Email = "dev#gmail.com";
user.CreatedAt = DateTime.Now;
await userManger.CreateAsync(user, "Admin111$$");
}
}
There are multiple ways to do this, I dont know the exact structure of your model but the log should be the same regardless:
First - Hard the value in:
public static async Task SeedEmployee(this UserManager<Employee> userManger)
{
if (await userManger.Users.AnyAsync())
{
return;
}
var user = new Employee();
user.FullName = "System Developer";
user.UserName = "dev#gmail.com";
user.Email = "dev#gmail.com";
user.CreatedAt = DateTime.Now;
user.DepartmentId = 1; //here
await userManger.CreateAsync(user, "Admin111$$");
}
Second - Return the departments you add, then pass it as parameter:
public static IHost SeedDb(this IHost webHost)
{
using var scope = webHost.Services.CreateScope();
try
{
var context = scope.ServiceProvider.GetRequiredService<HRSDbContext>();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<Employee>>();
var departments = context.SeedDepartment().Wait();
userManager.SeedEmployee(departments.First().Id ).Wait();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
return webHost;
}
public static async Task<IEnumerable<Department>> SeedDepartment(this HRSDbContext _db)
{
var _departments = await _db.Departments.AllAsync()
if (_departments != null)
{
return _departments;
}
var departments = new List<Department>();
var department = new Department();
department.Name = "A1";
department.Id = 1;
department.CreatedAt = DateTime.Now;
var department2 = new Department();
department2.Name = "A2";
department2.Id = 2;
department2.CreatedAt = DateTime.Now;
departments.Add(department);
departments.Add(department2);
await _db.Departments.AddRangeAsync(departments);
await _db.SaveChangesAsync();
return departments;
}
public static async Task SeedEmployee(this UserManager<Employee> userManger, int departmentId)
{
if (await userManger.Users.AnyAsync())
{
return;
}
var user = new Employee();
user.FullName = "System Developer";
user.UserName = "dev#gmail.com";
user.Email = "dev#gmail.com";
user.CreatedAt = DateTime.Now;
user.DepartmentId = departmentId;
await userManger.CreateAsync(user, "Admin111$$");
}
I have referred the Trying to call simple POST API from console App in VS2019. But, need to pass XML method in post instead of JSON . Any suggestions ?
static async Task Main(string[] args)
{
var TicketTask = await createTicket();
}
async static Task<string> createTicket()
{
var content = "unknown error";
using (var httpClient = new System.Net.Http.HttpClient())
{
using (var request = new System.Net.Http.HttpRequestMessage(new HttpMethod("POST"), "http://1.0.01.1/slive/"))
{
try
{
var base64authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes("username:password"));
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64authorization}");
request.Content = new StringContent("<soapenv:Envelope xmlns:xsi...", Encoding.UTF8, "application/xml"); ????? need to post a xml method here
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("text/xml");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpResponseMessage response = await httpClient.SendAsync(request).ConfigureAwait(false);
content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
Console.WriteLine(response);
}
catch (Exception ex)
{
content = ex.Message;
}
}
}
return content;
Found the solution, please correct me if there is a better way:
async static Task<string> createTicket2()
{
var content = "unknown error";
using (var httpClient = new System.Net.Http.HttpClient())
{
using (var request = new System.Net.Http.HttpRequestMessage(new HttpMethod("POST"), "http://10/sap-lve/"))
{
try
{
var base64authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes("an:s"));
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64authorization}");
String str1 = #"<s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'><s:Body><Get_api_version xmlns='http://e.s.a.com'/></s:Body></s:Envelope>";
**request.Content = new StringContent(str1, Encoding.UTF8, "text/xml");** ;
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("text/xml");
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpResponseMessage response = await httpClient.SendAsync(request).ConfigureAwait(false);
content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
//Console.WriteLine(response);
var result = response.Content.ReadAsStringAsync();
Console.WriteLine(result.Result);
}
catch (Exception ex)
{
content = ex.Message;
}
}
}
return content;
}
I want to send image files to SQL Server using C#.
The below code is working and saving files and their paths into the database. I need the same data in my API endpoint's response. I've created a custom response class, called RegistrationResponse.
I'm beginner in this so I'm looking for help.
public async Task<RegistrationResponse> PostFormData(HttpRequestMessage request)
{
object data = "";
NameValueCollection col = HttpContext.Current.Request.Form;
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/images");
var provider = new MultipartFormDataStreamProvider(root);
// Read the form data and return an async task.
var task = Request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
}
//read file data
foreach (MultipartFileData dataItem in provider.FileData)
{
try
{
string description = string.Empty;
string userId = string.Empty;
String fileName = string.Empty;
// Show all the key-value pairs.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
if (key.ToString().ToLower() == "userid")
{
userId = val;
}
else if (key.ToString().ToLower() == "description")
{
description = val;
}
}
}
String name = dataItem.Headers.ContentDisposition.FileName.Replace("\"", "");
fileName = userId + Path.GetExtension(name);
File.Move(dataItem.LocalFileName, Path.Combine(root, fileName));
using (var db = new AlumniDBEntities())
{
//saving path and data in database table
Post userPost = new Post();
userPost.Files = fileName;
userPost.Description = description;
userPost.UserID = Convert.ToInt32(userId);
userPost.CreatedDate = DateTime.Now;
db.Posts.Add(userPost);
db.SaveChanges();
data = db.Posts.Where(x => x.PostID ==
userPost.PostID).FirstOrDefault();
string output = JsonConvert.SerializeObject(data);
}
}
catch (Exception ex)
{
return Request.CreateResponse(ex);
}
}
return Request.CreateResponse(HttpStatusCode.Created);
});
var response = new RegistrationResponse
{
success = true,
status = HttpStatusCode.OK,
message = "Success",
data = data
};
return response;
}
I'm adding confirmation email feature to my ASP.NET WebAPI project. The server can send email fine, however, the confirmation link always return "Invalid token".
I checked some reasons as pointed out here
http://tech.trailmax.info/2015/05/asp-net-identity-invalid-token-for-password-reset-or-email-confirmation/
but it seems that none of them is the root cause
Below is my code:
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result;
result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
try
{
await userManager.AddToRoleAsync(user.Id, "Player");
//Generate email confirmation token
//var provider = new DpapiDataProtectionProvider("GSEP");
var provider = new MachineKeyProtectionProvider();
userManager.UserTokenProvider = new DataProtectorTokenProvider<GSEPUser>(provider.Create("EmailConfirmation"));
var code = await userManager.GenerateEmailConfirmationTokenAsync(user.Id);
code = System.Web.HttpUtility.UrlEncode(code);
EmailHelper emailHelper = new EmailHelper();
string callBackUrl = emailHelper.GetCallBackUrl(user, code);
EmailMessage message = new EmailMessage();
message.Body = callBackUrl;
message.Destination = user.Email;
message.Subject = "GSEP Account confirmation";
emailHelper.sendMail(message);
}
catch (Exception e)
{
return Ok(GSEPWebAPI.App_Start.Constants.ErrorException(e));
}
}
And now is EmailHelper
public class EmailHelper
{
public string GetCallBackUrl(GSEPUser user, string code)
{
var newRouteValues = new RouteValueDictionary(new { userId = user.Id, code = code });
newRouteValues.Add("httproute", true);
UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext, RouteTable.Routes);
string callbackUrl = urlHelper.Action(
"ConfirmEmail",
"Account",
newRouteValues,
HttpContext.Current.Request.Url.Scheme
);
return callbackUrl;
}
public void sendMail(EmailMessage message)
{
#region formatter
string text = string.Format("Please click on this link to {0}: {1}", message.Subject, message.Body);
string html = "Please confirm your account by clicking this link: link<br/>";
html += HttpUtility.HtmlEncode(#"Or click on the copy the following link on the browser:" + message.Body);
#endregion
MailMessage msg = new MailMessage();
msg.From = new MailAddress("myemail#example.com");
msg.To.Add(new MailAddress(message.Destination));
msg.Subject = message.Subject;
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));
SmtpClient smtpClient = new SmtpClient("smtp-mail.outlook.com", Convert.ToInt32(587));
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("myemail#example.com", "mypassword!");
smtpClient.Credentials = credentials;
smtpClient.EnableSsl = true;
smtpClient.Send(msg);
}
}
And 2 MachineKey class
public class MachineKeyProtectionProvider : IDataProtectionProvider
{
public IDataProtector Create(params string[] purposes)
{
return new MachineKeyDataProtector(purposes);
}
}
public class MachineKeyDataProtector : IDataProtector
{
private readonly string[] _purposes;
public MachineKeyDataProtector(string[] purposes)
{
_purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
return MachineKey.Protect(userData, _purposes);
}
public byte[] Unprotect(byte[] protectedData)
{
return MachineKey.Unprotect(protectedData, _purposes);
}
}
I also added machineKey tag in Web.config as some instruction pointed out.
And finally is my confirmation email API
[AllowAnonymous]
[HttpGet]
public async Task<IHttpActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return Ok("Confirm error");
}
IdentityResult result;
try
{
result = await UserManager.ConfirmEmailAsync(userId, code);
}
catch (InvalidOperationException ioe)
{
// ConfirmEmailAsync throws when the userId is not found.
return Ok("UserID not found");
}
if (result.Succeeded)
{
return Ok("Confirmation succesfully");
}
else
{
return Ok(result.Errors);
}
}
Please show me where am I go wrong
I know this is an old thread. But I though of adding the answer as it could help others.
You are using the below code
string callbackUrl = urlHelper.Action(
"ConfirmEmail",
"Account",
newRouteValues,
HttpContext.Current.Request.Url.Scheme
);
and the UrlHelper.Action already does the url encoding for you in the latest MVC versions. So here in your code you are doing the encoding twice (one inside the Register and another inside GetCallBackUrl using urlHelper.Action) and that is why you are getting the invalid token error.
I have a really simple ASP.NET Api Controller with one method.
public HttpResponseMessage<User> Post(User user)
{
return new HttpResponseMessage<User>(new User() { Name = "New User at Server" });
}
My debugger says that the method is called but the problem is that the parameter "user" has all its content set to null; I am using Fiddler to look at request and response.. and all looks good.
This is my service code in the client.
public void AddUser(Models.User user, Action<Models.User> ShowResult)
{
var uiThreadScheduler = TaskScheduler.FromCurrentSynchronizationContext();
string url = "http://localhost:4921/User";
Uri uri = new Uri(url, UriKind.Absolute);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
var sendWebPost = Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null)
.ContinueWith(task =>
{
Tuple<string, string>[] stringToSend = { Tuple.Create<string, string>("user", ObjectToJson<Models.User>(user)) };
var bytesToSend = GetRequestBytes(stringToSend);
using (var stream = task.Result)
stream.Write(bytesToSend, 0, bytesToSend.Length);
}
).ContinueWith(task =>
{
Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null)
.ContinueWith<WebResponse>(task2 => { ValidateResponse(task2); return task2.Result; })
.ContinueWith<Models.User>(task3 => {return JsonToObject<Models.User>(task3);})
.ContinueWith(task4 => { TryClearWorking(); ShowResult(task4.Result); }, uiThreadScheduler);
});;
}
public static string ObjectToJson<T>(T obj) where T : class
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
MemoryStream stream = new MemoryStream();
StreamReader sr = new StreamReader(stream);
serializer.WriteObject(stream, obj);
sr.BaseStream.Position = 0;
string jsonString = sr.ReadToEnd();
return jsonString;
}
protected static byte[] GetRequestBytes(Tuple<string, string>[] postParameters)
{
if (postParameters == null || postParameters.Length == 0)
return new byte[0];
var sb = new StringBuilder();
foreach (var key in postParameters)
sb.Append(key.Item1 + "=" + key.Item2 + "&");
sb.Length = sb.Length - 1;
return Encoding.UTF8.GetBytes(sb.ToString());
}
Anyone who can give me some ideas where to start to look for errors.....
You need to set the Content-Length header.