Reading appsettings.json values in asp.netcore - json

I am trying to read some values from my appsettings.json file for Basic Authentication. Locally the code works fine but I'm confused on How can I do it when I am deploying my application live.
My appsettings.json file look like this
appsettings.json
{
"BasicAuth": {
"UserName": "admin",
"Password": "1234567789"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
}
The code that I am using for my middleware looks like this
startup.cs
public void ConfigureServices(IServiceCollection
{
services.AddHttpClient("MyClient", client => {
client.BaseAddress = new Uri("http://xx.xx.xx.xxx/1/#/nutch/query");
client.DefaultRequestHeaders.Add("username", "admin");
client.DefaultRequestHeaders.Add("password", "1234567789");
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMiddleware<BasicAuthMiddleware>("http://xx.xx.xx.xxx/abc/#/1/query/");
}
And My Middleware Class looks like this
BasicAuthMiddleware.cs
As you can see I have to send the whole path to my appsettings.json file in .AddJsonFile
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace searchEngineTesting.Controllers
{
public class BasicAuthMiddleware
{
private readonly RequestDelegate _next;
private readonly string _realm;
public BasicAuthMiddleware(RequestDelegate next, string realm)
{
_next = next;
_realm = realm;
}
public async Task Invoke(HttpContext context)
{
string authHeader = context.Request.Headers["Authorization"];
if (authHeader != null && authHeader.StartsWith("Basic "))
{
// Get the encoded username and password
var encodedUsernamePassword = authHeader.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries)[1]?.Trim();
// Decode from Base64 to string
var decodedUsernamePassword = Encoding.UTF8.GetString(Convert.FromBase64String(encodedUsernamePassword));
// Split username and password
var username = decodedUsernamePassword.Split(':', 2)[0];
var password = decodedUsernamePassword.Split(':', 2)[1];
// Check if login is correct
if (IsAuthorized(username, password))
{
await _next.Invoke(context);
return;
}
}
// Return authentication type (causes browser to show login dialog)
context.Response.Headers["WWW-Authenticate"] = "Basic";
// Add realm if it is not null
if (!string.IsNullOrWhiteSpace(_realm))
{
context.Response.Headers["WWW-Authenticate"] += $" realm=\"{_realm}\"";
}
// Return unauthorized
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
}
// Make your own implementation of this
public bool IsAuthorized(string username, string password)
{
//IConfiguration config = new ConfigurationBuilder()
// .AddJsonFile("appsettings.json", true, true)
// .Build();
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("C:/programfiles/path/to/appsettings.json")
.Build();
var basicAuthUserName = config["BasicAuth:UserName"];
var basicAuthPassword = config["BasicAuth:Password"];
// Check that username and password are correct
return username.Equals(basicAuthUserName, StringComparison.InvariantCultureIgnoreCase)
&& password.Equals(basicAuthPassword);
}
}
}
I have tried only by giving name appsettings.json rather than giving the whole path, but it doesn't work, and the exception occurs of cannot find appsettings.json file. How can I give it a generalize path, so that I don't have to change it again and again, and I can read the values.

You can inject IConfiguration in your middleware constructor. No need to use the config builder.
private readonly RequestDelegate _next;
private readonly string _realm;
private readonly IConfiguration _configuration;
public BasicAuthMiddleware(RequestDelegate next, string realm, IConfiguration configuration)
{
_next = next;
_realm = realm;
_configuration = configuration;
}

Related

HttpPost with JSON parameter is not working in ASP.NET Core 3

So, I migrated my RestAPI project to ASP.NET Core 3.0 from ASP.NET Core 2.1 and the HttpPost function that previously worked stopped working.
[AllowAnonymous]
[HttpPost]
public IActionResult Login([FromBody]Application login)
{
_logger.LogInfo("Starting Login Process...");
IActionResult response = Unauthorized();
var user = AuthenticateUser(login);
if (user != null)
{
_logger.LogInfo("User is Authenticated");
var tokenString = GenerateJSONWebToken(user);
_logger.LogInfo("Adding token to cache");
AddToCache(login.AppName, tokenString);
response = Ok(new { token = tokenString });
_logger.LogInfo("Response received successfully");
}
return response;
}
Now, the login object has null values for each property. I read here, that
By default, when you call AddMvc() in Startup.cs, a JSON formatter, JsonInputFormatter, is automatically configured, but you can add additional formatters if you need to, for example to bind XML to an object.
Since AddMvc was removed in aspnetcore 3.0, now I feel this is why I am unable to get my JSON object anymore. My Startup class Configure function looks like this:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseRouting();
//app.UseAuthorization();
//app.UseMvc(options
// /*routes => {
// routes.MapRoute("default", "{controller=Values}/{action}/{id?}");
//}*/);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
}
The request I am sending through postman (raw and JSON options are selected)
{
"AppName":"XAMS",
"licenseKey": "XAMSLicenseKey"
}
UPDATES
Postman Header: Content-Type:application/json
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//_logger.LogInformation("Starting Log..."); //shows in output window
services.AddSingleton<ILoggerManager, LoggerManager>();
services.AddMemoryCache();
services.AddDbContext<GEContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
//services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddControllers();
services.AddRazorPages();
//Authentication
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = "https://localhost:44387/";
options.Audience = "JWT:Issuer";
options.TokenValidationParameters.ValidateLifetime = true;
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(5);
options.RequireHttpsMetadata = false;
});
services.AddAuthorization(options =>
{
options.AddPolicy("GuidelineReader", p => {
p.RequireClaim("[url]", "GuidelineReader");
});
});
//
}
Application.cs
public class Application
{
public string AppName;
public string licenseKey;
}
With you updated code, I think the reason is you didn't create setter for your properties.
To fix the issue, change your Application model as below:
public class Application
{
public string AppName {get;set;}
public string licenseKey {get;set;}
}

post_logout_redirect_uri ASP NET Core 2.2 AzureAD Razor Class Library RCL

We have tried using the sample
https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/
Walked through the sample and all works.
We can't get it to redirect after logout process. Also, it seems the account controller is not there but it is called in _layout.chtml this must be something new.
Yes, it does redirect to the application - what I'd like it to do is redirect to a different page.
You can redirect user to another page after sign-out by setting the OnSignedOutCallbackRedirect event :
In Startup.cs add using System.Threading.Tasks;
Config your new redirect url in OnSignedOutCallbackRedirect event :
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = false;
options.Events.OnSignedOutCallbackRedirect = (context) =>
{
context.Response.Redirect("/Home/About");
context.HandleResponse();
return Task.CompletedTask;
};
});
The account controller code is built into the framework now. You can see it in Microsoft.AspNetCore.Authentication.AzureAD.UI.AzureAD.Controllers.Internal (see https://github.com/aspnet/AADIntegration/blob/0efa96de73e3235fbfc55cfe51d9547a693010cc/src/Microsoft.AspNetCore.Authentication.AzureAD.UI/Areas/AzureAD/Controllers/AccountController.cs):
namespace Microsoft.AspNetCore.Authentication.AzureAD.UI.AzureAD.Controllers.Internal
{
[AllowAnonymous]
[Area("AzureAD")]
[NonController]
[Route("[area]/[controller]/[action]")]
internal class AccountController : Controller
{
public IOptionsMonitor<AzureADOptions> Options
{
get;
}
public AccountController(IOptionsMonitor<AzureADOptions> options)
{
this.Options = options;
}
[HttpGet("{scheme?}")]
public IActionResult SignIn([FromRoute] string scheme)
{
scheme = scheme ?? AzureADDefaults.AuthenticationScheme;
string str = base.Url.Content("~/");
return this.Challenge(new AuthenticationProperties()
{
RedirectUri = str
}, new String[] { scheme });
}
[HttpGet("{scheme?}")]
public IActionResult SignOut([FromRoute] string scheme)
{
scheme = scheme ?? AzureADDefaults.AuthenticationScheme;
AzureADOptions azureADOption = this.Options.Get(scheme);
string str = base.Url.Page("/Account/SignedOut", null, null, base.Request.Scheme);
return this.SignOut(new AuthenticationProperties()
{
RedirectUri = str
}, new String[] { azureADOption.CookieSchemeName, azureADOption.OpenIdConnectSchemeName });
}
}
}
Unfortunately, I have not be able to force a redirect after logout. Instead, I see a page that says "You have successfully signed out." I'd like to know how to redirect the user back to the Index page.
I had to override the signedOut page manually by adding this to a controller:
[AllowAnonymous]
[HttpGet]
[Route("/MicrosoftIdentity/Account/SignedOut")]
public IActionResult SignedOut()
{
return Redirect(<MyRealSignedOutRedirectUri>);
}

Azure MobileSeviceClient InvokeApiAsync - Newtonsoft.Json.JsonReaderException

I'm trying to call a method on a custom api controller on my azure mobile services client.
If I hit the path in the browser it returns data just fine. When trying to call it from my app I get the following error
"Newtonsoft.Json.JsonReaderException: Error reading string. Unexpected token: StartObject. Path '', line 1, position 1."
public async Task<string> AuthUser (string email, string pass)
{
var id = await client.InvokeApiAsync<string>(
"Login/AuthUser",
System.Net.Http.HttpMethod.Get,
new Dictionary<string, string>() {
{"emailAddress", email },
{"password",pass }
}
);
if (id != null)
{
return id.ToString();
}
else
{
return "";
}
}
Here's the controller I'm calling
using System.Linq;
using System.Web.Http;
using System.Web.Http.Description;
using MyAppService.DataObjects;
using MyAppService.Models;
using Microsoft.Azure.Mobile.Server.Config;
namespace MyAppService.Controllers
{
[MobileAppController]
public class LoginController : ApiController
{
private MyAppContext db = new MyAppContext ();
[HttpGet]
[ActionName("AuthUser")]
public IHttpActionResult Login(string emailAddress, string password)
{
var login = db.Members.FirstOrDefault(m => m.Email == emailAddress && m.Password == password);
if (login != null)
{
return Ok(new {Id = login.Id });
}
else
{
return Unauthorized();
}
}
}
}
EDIT: The issue was the return type from the controller. Changed it to string and it worked.
The issue was the return type from the controller. Changed it to string and it worked

vNext: Console app that uses razor views without hosting

I am creating console application that does some file conversions. These conversions are easily done creating a model from the input file and then executing razor models for the output.
To have this working in the IDE I used Visual Studio 2015 preview and created a vnext console application that uses MVC. (You get razor support out of the box then). To get this all working you need to host the MVC app though, and the cheapest way to do that is hosting is through a WebListener. So I host the MVC app and then call it through "http://localhost:5003/etc/etc" to get the rendered views that construct the output.
But the console app is not supposed to listen to/use a port. It is just a command line tool for file conversions. If multiple instances would run at the same time they would fight to host the pages on the same port. (This could of coarse be prevented by choosing a port dynamically, but this is not what I am looking for)
So my question is how would you get this working without using a port, but using as much of the vnext frameworks as possible.
In short: how can I use cshtml files that I pass models in a console app that does not use a port using the vnext razor engine.
Here is some code I currently use:
Program.cs
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Fallback;
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace ConsoleTest
{
public class Program
{
private readonly IServiceProvider _hostServiceProvider;
public Program(IServiceProvider hostServiceProvider)
{
_hostServiceProvider = hostServiceProvider;
}
public async Task<string> GetWebpageAsync()
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("http://localhost:5003/home/svg?idx=1");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));
return await httpClient.GetStringAsync("");
}
}
public Task<int> Main(string[] args)
{
var config = new Configuration();
config.AddCommandLine(args);
var serviceCollection = new ServiceCollection();
serviceCollection.Add(HostingServices.GetDefaultServices(config));
serviceCollection.AddInstance<IHostingEnvironment>(new HostingEnvironment() { WebRoot = "wwwroot" });
var services = serviceCollection.BuildServiceProvider(_hostServiceProvider);
var context = new HostingContext()
{
Services = services,
Configuration = config,
ServerName = "Microsoft.AspNet.Server.WebListener",
ApplicationName = "ConsoleTest"
};
var engine = services.GetService<IHostingEngine>();
if (engine == null)
{
throw new Exception("TODO: IHostingEngine service not available exception");
}
using (engine.Start(context))
{
var tst = GetWebpageAsync();
tst.Wait();
File.WriteAllText(#"C:\\result.svg", tst.Result.TrimStart());
Console.WriteLine("Started the server..");
Console.WriteLine("Press any key to stop the server");
Console.ReadLine();
}
return Task.FromResult(0);
}
}
}
Startup.cs
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.ConfigurationModel;
namespace ConsoleTest
{
public class Startup
{
public IConfiguration Configuration { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
//Configure WebFx
app.UseMvc(routes =>
{
routes.MapRoute(
null,
"{controller}/{action}",
new { controller = "Home", action = "Index" });
});
}
}
}
I solved it using the following code:
Program.cs
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.TestHost;
using Microsoft.AspNet.Builder;
using Microsoft.Framework.Runtime.Infrastructure;
namespace ConsoleTest
{
public class Program
{
private Action<IApplicationBuilder> _app;
private IServiceProvider _services;
public async Task<string> TestMe()
{
var server = TestServer.Create(_services, _app);
var client = server.CreateClient();
return await client.GetStringAsync("http://localhost/home/svg?idx=1");
}
public void Main(string[] args)
{
_services = CallContextServiceLocator.Locator.ServiceProvider;
_app = new Startup().Configure;
var x = TestMe();
x.Wait();
Console.WriteLine(x.Result);
Console.ReadLine();
}
}
}
Startup.cs
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
using Microsoft.AspNet.Routing;
namespace ConsoleTest
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseServices(services =>
{
// Add MVC services to the services container
services.AddMvc();
});
//Configure WebFx
app.UseMvc(routes =>
{
routes.MapRoute(
null,
"{controller}/{action}",
new { controller = "Home", action = "Index" });
});
}
}
}

How can I save a JSON response to a file in unity3D for ios and android

I'm working on a 2D mobile game for ios and android using Unity3D.
The game requires to save a JSON response to a file.
I use NGUI and MiniJSON for that.
I want to know how to implement that starting from www function to get JSOn response and save it to a file(including path) and load it from other script.
if it is too much, just give me a example for that.
Thank you
I haven't tested the code yet, but it might give you an idea :-)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
public class WWWJsonTest : MonoBehaviour
{
private const float SECONDS_BEFORE_TIMEOUT = 10;
private const string URL = "INSERT URL HERE";
private const string FILE_PATH = "INSERT FILE PATH";
public void DownloadAndSave()
{
StartCoroutine(DownloadCoroutine());
}
public Dictionary<object, object> GetSavedData()
{
// Use ReadContents() and do your MiniJSON magic here
return null;
}
private IEnumerator DownloadCoroutine()
{
var requestHeaders = new Hashtable()
{
{ "Connection", "close"},
{ "Accept", "application/json"}
};
using(var request = new WWW(URL, null, requestHeaders))
{
float timeStarted = Time.realtimeSinceStartup;
while(!request.isDone)
{
// Check if the download times out
if(Time.realtimeSinceStartup - timeStarted > SECONDS_BEFORE_TIMEOUT)
{
Debug.Log("Download timed out");
yield break;
}
yield return null;
}
// Check for other errors
if(request.error != null)
{
Debug.Log(request.error);
yield break;
}
SaveContents(request.text);
}
}
private string ReadContents()
{
string ret;
using(FileStream fs = new FileStream(FILE_PATH, FileMode.Open))
{
BinaryReader fileReader = new BinaryReader(fs);
ret = fileReader.ReadString();
fs.Close();
}
return ret;
}
private void SaveContents(string text)
{
using(FileStream fs = new FileStream(FILE_PATH, FileMode.Create))
{
BinaryWriter fileWriter = new BinaryWriter(fs);
fileWriter.Write(text);
fs.Close();
}
}
}