Asp.NET core, AJAX doesn't work at all in my project - asp.net

I started a Razor Pages project and I need to use AJAX so that I can refresh my comments section without refreshing my entire page. unfortunately AJAX does not seem to work at all, it's as if the code was never there.
I thought it was just because I couldn't connect my buttons to the script, but even the code that's supposed to run upon (document).ready does nothing. So I am at a loss.
here is some test code I'm trying to run:
<button id="buttonDemo1" >THE AJAX BUTTON</button>
#section Scripts
{
<script >
//edit: threw console.log around, nothing shows up in the browser console
$(document).ready(function () {
console.log("ready2!!");
var url = '#Url.Action("TEST", "ChatRoom")';
$('#buttonDemo1').click(function () {
console.log("THE FORBIDDEN BUTTON HAS BEEN PRESSED!");
$.ajax({
type: 'GET',
url: url,
success: function (result) {
alert("ajax success");
}
});
});
});
$(document).ready(function(){
console.log("ready!!");
$.ajax({
type: "POST",
url: '#Url.Action("TEST", "ChatRoom")',
data: {
},
success: function (response) {
console.log("success");
alert("ajax success")
},
failure: function () {
console.log("fail");
alert("ajax fail");
},
error: function (response) {
console.log("error");
alert(response.responseText)
}
});
}
</script>
}
Here is my Program.cs:
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Scratch.Data;
using Microsoft.AspNetCore.Authorization;
using Newtonsoft.Json.Serialization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddControllersWithViews();
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddMvc();
builder.Services.AddRazorPages();
builder.Services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._#+";
options.User.RequireUniqueEmail = false;
});
builder.Services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = "/Identity/Account/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
});
//this forces authorisation to be required on all pages that don't have the [AllowAnonymous] tag
/*builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});*/
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();;
app.UseAuthorization();
app.MapRazorPages();
//trying to add mvc to the project
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
//chathub doesn't exist
//endpoints.MapHub<ChatHub>("/chathub");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
app.Run();
I must be missing something critical, do I need to install some NuGet package, or is there something I need to add to my Program.cs file? Any suggestions would be much appreciated.

I couldn't connect my buttons to the script, but even the code that's
supposed to run upon (document).ready does nothing. So I am at a loss.
The way you are trying to call your button event is incorrect; so your functionality shouldn't work in this fashision for sure because you are using $(document).ready(function() twice within the same script section and this causing the issue.
I must be missing something critical, do I need to install some NuGet
package, or is there something I need to add to my Program.cs file?
No, you don't need any nuget package or any middleware referece within your prgram.cs file. You can resolve your issue by ommiting one additional $(document).ready section.
Solution:
You should use single $(document).ready(function() within the script and within that block you should please your all the function. You can try as following:
HTML:
button id="buttonDemo1">THE AJAX BUTTON</button>
Script:
#section Scripts
{
<script>
//edit: threw console.log around, nothing shows up in the browser console
$(document).ready(function () {
alert("Click");
console.log("ready2!!");
var url = '#Url.Action("TEST", "ChatRoom")';
$('#buttonDemo1').click(function () {
alert("buttonDemo1 Click");
console.log("THE FORBIDDEN BUTTON HAS BEEN PRESSED!");
$.ajax({
type: 'GET',
url: url,
success: function (result) {
alert("ajax success");
}
});
});
});
</script>
}
Note: Your second ajax functional seems doing nothing so I haven't included that. If you need that you can include that within the same document.ready function but in another function block.
Output:

Related

SSO with openiddict set login page absolute url

I am using openiddict for custom sso and want to host login ui on a separate domain in spa application. The issue I am facing is propper configuration of challenge action.
I've tried to overwrite OnRedirectToLogin event but that obviously not working
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.Events = new CookieAuthenticationEvents()
{
OnRedirectToLogin = async (context) =>
{
context.HttpContext.Response.Redirect("https://example.com/account/login");
}
};
});
Am I doing smth wrong?
The solution to the following issue was found in this answer
Code to add:
services.ConfigureApplicationCookie(options =>
{
options.Events.OnRedirectToLogin = context =>
{
context.HttpContext.Response.Redirect("http://example.com/login");
return Task.CompletedTask;
};
});

Middleware Ordering

I have a new .NET Core 3.1 app and am struggling with the concept of Middleware. From reading around, it seems the order of including different middlewares is important. I currently have several problems which I can't seem to solve:
I never see the developer error page, and have to check the event log to see what's happened if there's an error. I just get the blank "error 500" etc pages from Chrome. The custom error pages also never display when there's a 500/400.
The app always tries to redirect me to /Account/Login despite changing this in the cookie settings.
User.IsAuthenticated returns false when the CheckPermissionsAction call is made in Elmah, so I can't access Elmah. The User.IsInRole call works for from controllers though.
This is how I'm bootstrapping the app. It feels like something is overriding the settings:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<DataProtectionTokenProviderOptions>(options =>
options.TokenLifespan = TimeSpan.FromDays(2));
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(30);
});
services.AddControllersWithViews();
services.AddTransient<IUserStore<User>, UserStore>();
services.AddTransient<IRoleStore<IdentityRole>, RoleStore>();
services.AddRazorPages();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = new PathString("/login");
options.AccessDeniedPath = new PathString("/error/denied");
options.LogoutPath = new PathString("/log-off");
options.ExpireTimeSpan = TimeSpan.FromDays(60);
options.SlidingExpiration = true;
options.Cookie.HttpOnly = true;
options.Cookie.Name = "MyCookie";
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.Cookie.SameSite = SameSiteMode.Lax;
});
services.AddIdentity<User, IdentityRole>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequiredLength = 6;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
})
.AddUserStore<UserStore>()
.AddRoleStore<RoleStore>()
.AddDefaultTokenProviders();
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddElmah<SqlErrorLog>(options =>
{
options.ConnectionString = Configuration.GetConnectionString("MyApp");
options.CheckPermissionAction = (context)=>{
return context.User.Identity.IsAuthenticated && context.User.IsInRole(RoleHelper.SuperAdmin);
};
options.Path = "/elmah";
});
services.AddSingleton<IAppConfiguration, AppConfiguration>(e => Configuration.GetSection("AppConfig")
.Get<AppConfiguration>());
OptionsConfigurationServiceCollectionExtensions.Configure<DbHelper>(services, Configuration.GetSection("ConnectionStrings"));
services.AddHttpContextAccessor();
}
public void ConfigureContainer(ContainerBuilder builder)
{
// wire up using autofac specific APIs here
builder.Register(context => new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, MyDetailsViewModel>();
})).AsSelf().SingleInstance();
builder.RegisterModule(new RegistrationModule()); // separate assembly, wires up autofac registrations
builder.Register(c =>
{
//This resolves a new context that can be used later.
var context = c.Resolve<IComponentContext>();
var config = context.Resolve<MapperConfiguration>();
return config.CreateMapper(context.Resolve);
})
.As<IMapper>()
.InstancePerLifetimeScope();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
// debugger shows this section is called, but I never see the error page.
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseRouteDebugger();
}
else
{
app.UseExceptionHandler("/error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseSession();
app.UseElmah();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
var cookiePolicyOptions = new CookiePolicyOptions
{
Secure = CookieSecurePolicy.SameAsRequest,
MinimumSameSitePolicy = SameSiteMode.None
};
app.UseCookiePolicy(cookiePolicyOptions);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Guest}/{action=Index}/{id?}");
endpoints.MapRazorPages();
endpoints.MapControllers();
});
app.UseStatusCodePages(async ctx =>
{
//Re-execute the request so the user gets the error page
string originalPath = ctx.HttpContext.Request.Path.Value;
switch (ctx.HttpContext.Response.StatusCode)
{
case 401:
//Re-execute the request so the user gets the error page
ctx.HttpContext.Items["originalPath"] = originalPath;
ctx.HttpContext.Request.Path = "/error/denied";
break;
case 412:
ctx.HttpContext.Items["originalPath"] = originalPath;
ctx.HttpContext.Request.Path = "/error/expired-account";
break;
case 404:
ctx.HttpContext.Items["originalPath"] = originalPath;
ctx.HttpContext.Request.Path = "/error/not-found";
break;
case 500:
ctx.HttpContext.Items["originalPath"] = originalPath;
ctx.HttpContext.Request.Path = "/error/not-found";
break;
}
});
DapperExtensions.DapperExtensions.SetMappingAssemblies(new[]
{
Assembly.GetAssembly(typeof(MyApp.Domain.Model.Note)),
Assembly.GetExecutingAssembly()
});
}
In regards to the order of your middleware, there is a problem with it.
There is a section in the Microsoft docs dedicated to the order of middleware, I suggest reading it.
As for your middleware, the correct order would be:
app.UseHttpsRedirection();
app.UseStatusCodePages(async ctx =>
{
// Omitted for brevity.
});
app.UseStaticFiles();
var cookiePolicyOptions = new CookiePolicyOptions
{
// Omitted for brevity.
};
app.UseCookiePolicy(cookiePolicyOptions);
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
// If the app uses session state, call Session Middleware after Cookie
// Policy Middleware and before MVC Middleware.
app.UseSession();
app.UseElmah(); // Not sure about this one. I don't know what it's supposed to do?
app.UseEndpoints(endpoints =>
{
// Omitted for brevity.
});
DapperExtensions.DapperExtensions.SetMappingAssemblies(new[]
{
// Omitted for brevity.
});

ASP.NET Core 2.2 MVC problem redirecting after signing in

I have recently been experiencing an issue when attempting to login on the web app that I am working on, I did not modify the Startup.cs file and it used to work last time when I used it, but now when I am trying to log in it redirects me back to the Login page, although signing in succeeds
var result = await _signInManager.PasswordSignInAsync(user.UserName,
model.Password, model.RememberMe, lockoutOnFailure: true);
if (result.Succeeded)
{
// return LocalRedirect(returnUrl);
return RedirectToAction(nameof(HomeController.Index), "Home");
}
it hits the RetirectToAction, but I am sent back to Login Page, also I see two statuses in the network console, 200 and 302 which should be ok
Just a little update, after trying different things it looks like the signInManager does not sign me in at all
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<AORContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<IdentityUser, IdentityRole>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<AORContext>();
services.Configure<IdentityOptions>(options =>
{
// Default User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._#+";
options.User.RequireUniqueEmail = true;
});
services.Configure<IdentityOptions>(options =>
{
// Default Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 0;
});
services.ConfigureApplicationCookie(options =>
{
options.AccessDeniedPath = "/Account/AccessDenied";
//options.Cookie.Name = "YourAppCookieName";
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
// ReturnUrlParameter requires
//using Microsoft.AspNetCore.Authentication.Cookies;
//options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
//options.SlidingExpiration = true;
});
services.AddMvc(config =>
{
// using Microsoft.AspNetCore.Mvc.Authorization;
// using Microsoft.AspNetCore.Authorization;
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
I had the same problem, and this feels more like a hack than anything but I got it work by redirecting the action back to itself with a flag. And if the flag is set, redirect to the actual target page:
// GET: LoginWithToken
[AllowAnonymous]
[HttpGet("LoginWithToken")]
public async Task<ActionResult> LoginWithToken(string token = null, bool tokenLoginSuccess = false)
{
// redirect
if (tokenLoginSuccess)
return RedirectToAction(nameof(Index));
// set cookie
await schoolLoginService.SignInWithToken(this.HttpContext, token);
return RedirectToAction(nameof(LoginWithToken), new { tokenLoginSuccess = true });
}

Sending requests from spa to .netcore web api using adaljs always returns 401

I have a spa that is sending a get request to a web api.
When I dont have the authorize attribute, I am able to get the values (of course!). Adding the authorize attribute always returns a 401 response.
After scratching my head on this for 2 weeks straight, I feel like only SO gods can help.
I have the following questions:
What am I doing wrong?
Is there a better way to do this?
How can I log the incoming token on the server side?
(Just so I can validate it at jwt.io)
Assuming my keys, tenant, client(id) etc are properly set up,
My code on spa is like this:
'use strict';
angular.module('todoApp')
.controller('homeCtrl', ['$scope', '$http', 'adalAuthenticationService', '$location', function ($scope, $http, adalService, $location) {
$scope.apiData = [];
$scope.login = function () {
adalService.login().then(function () {
console.log('yay');
});
};
$scope.logout = function () {
adalService.logOut();
};
$scope.isActive = function (viewLocation) {
return viewLocation === $location.path();
};
$scope.getData = function () {
// #1: Set up ADAL
var authContext = new AuthenticationContext({
clientId: 'myclientid',
postLogoutRedirectUri: window.location
});
var user = authContext.getCachedUser();
if (user) {
console.log(user);
console.log('Signed in as: ' + user.userName);
} else {
console.log('Not signed in');
}
var tokenStored;
authContext.acquireToken(
'https://graph.windows.net',
function (error, token) {
// TODO: Handle error obtaining access token
if (error || !token) {
console.log('Error no token');
return;
}
console.log("token is:" + token);
tokenStored = token;
$http.get('https://localhost:44301/api/values', {
headers: { 'Authorization': 'Bearer ' + tokenStored, }
}).then(function (response) {
$scope.apiData = response.data;
console.log(response);
alert('Data recieved');
});
});
};
}]);
My Api Startup.cs looks like this:
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//ToDo: Implement Logger Factory
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
// Shows UseCors with CorsPolicyBuilder.
// global policy - assign here or on each controller
app.UseCors("CorsPolicy");
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
// TokenValidationParameters = tokenValidationParameters
});
app.UseMvc();
}
My controller method looks like this
[Route("api/values")]
[Authorize]
[EnableCors("CorsPolicy")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IActionResult Get()
{
if (!HttpContext.User.Identity.IsAuthenticated)
{
var results = _interconnectCodesRepository.GetCodes();
return Ok(results);
}
else
{
return BadRequest();
}
}
}
}
Any suggestions or hints will be much appreciated.
Thanks
To get the token from .net core web API project, we can add AuthenticationFailed event like below:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAD:Tenant"]),
Audience = Configuration["AzureAd:Audience"],
Events = new JwtBearerEvents
{
OnAuthenticationFailed= AuthenticationFailed
}
});
private Task AuthenticationFailed(AuthenticationFailedContext authenticationFailedContext)
{
Debug.WriteLine(authenticationFailedContext.Request.Headers["authorization"]);
return Task.FromResult(0);
}
The token you were acquiring using the resrouce https://graph.windows.net in the code is for the Azure Graph REST instead of your API. There is no need to acquire the token manually in the client for the SPA application. The ADAL library will acquire and append the token based on the resource automatically. We just only need to init which endpoints we want to request. Here is the js code for your reference:
var myApp = angular.module('myApp', ['AdalAngular']).config(['$httpProvider', 'adalAuthenticationServiceProvider', function ($httpProvider, adalProvider) {
//{Array} endpoints - Collection of {Endpoint-ResourceId} used for automatically attaching tokens in webApi calls.
var endpoints = {
"https://localhost:44327/": "https://adfei.onmicrosoft.com/ToGoAPI",
};
adalProvider.init(
{
instance: 'https://login.microsoftonline.com/',
tenant: 'adfei.onmicrosoft.com',
clientId: 'e2354bba-e915-4cb8-a48d-bcda101b8603',
extraQueryParameter: 'nux=1',
endpoints: endpoints,
},
$httpProvider
);
}])
myApp.controller('homeCtrl', ['$scope', '$http', 'adalAuthenticationService', '$location', 'toGoListSvc', function ($scope, $http, adalService, $location, toGoListSvc) {
$scope.double = function (value) { return value * 2; };
$scope.login = function () {
adalService.login();
};
$scope.logout = function () {
adalService.logOut();
};
$scope.getData = function () {
$http.defaults.useXDomain = true;
delete $http.defaults.headers.common['X-Requested-With'];
$http.get('https://localhost:44327/api/ToGoList').success(function (results) {
console.log(results)
$scope.toGoList = results;
});
}
}]);
For the web API side, we need to specify the the Authority and Audience or other parameters as you wanted( refer the first piece of code).
On the Azure side, we need to register two web applications. One presents the client and the other presents the resource protected by Azure AD. For example, in my test scenario, I registered ToDoSPA and ToGoAPI and grant the permission as figure below:
And to make the ToDoSPA application integrate with Azure AD with implicit flow for the SPA app, we also need to modify its manifest to set the oauth2AllowImplicitFlow to true.
In addition, here are some helpful links about protecting the web API with Azure AD:
https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore
https://github.com/Azure-Samples/active-directory-angularjs-singlepageapp-dotnet-webapi
https://github.com/AzureAD/azure-activedirectory-library-for-js
Update( custom AudienceValidator)
// Configure the app to use Jwt Bearer Authentication
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
TokenValidationParameters=new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
{
AudienceValidator = (audiences, securityToken, validationParameters) =>
{
string[] allowedAudiences = { "https://adfei.onmicrosoft.com/TodoListService", "https://graph.windows.net" };
return allowedAudiences.Contains<string>(audiences.First<string>());
},
},
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAD:Tenant"]),
//Audience = Configuration["AzureAd:Audience"],
});

Parse urlencoded Message with IronRouter in Meteor

I am using http://mailin.io/doc to parse e-mails to my (future) Meteor application. Therefore I created a webhook using Iron-Router that should process the message and the attachments.
Using the following code, a { } is written in the console.
Router.route('/receive/', {where: 'server'})
.post(function(req, res) {
console.log(this.request.body);
});
I found some people reporting similar issues but the provided solutions don't work for me.
https://github.com/iron-meteor/iron-router/issues/909
https://github.com/iron-meteor/iron-router/issues/1003
Any ideas?
In the links the correct workaround was described, seems as is I had another error as well. The following code did the trick for me:
if (Meteor.isServer) {
var Busboy = Meteor.npmRequire("busboy"),
fs = Npm.require("fs"),
os = Npm.require("os"),
path = Npm.require("path");
Router.onBeforeAction(function (req, res, next) {
var filenames = []; // Store filenames and then pass them to request.
_.extend(req, {postData: {}});
if (req.method === "POST") {
var busboy = new Busboy({ headers: req.headers });
busboy.on("file", function (fieldname, file, filename, encoding, mimetype) {
var saveTo = path.join(os.tmpDir(), filename);
file.pipe(fs.createWriteStream(saveTo));
filenames.push(saveTo);
});
busboy.on("field", function(fieldname, value) {
req.postData[fieldname] = value;
});
busboy.on("finish", function () {
// Pass filenames to request
req.filenames = filenames;
next();
});
// Pass request to busboy
req.pipe(busboy);
} else {
this.next();
}
});
}
and the required route looks like this:
Router.route('/receive/', {where: 'server'})
.post(function() {
// Use this.request.postData to access the message content
postData = this.request.postData;
});

Resources