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
Related
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;
}
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;}
}
I am having problems deserialising JSON into its corresponding C# Object.
My server returns valid JSON: {"success":false,"message":"Please enter a valid Email Address."}
My server is using a Laravel project and code to return JSON is:
return response()->json(['success' => false, 'message' => 'Please enter a valid Email Address.']);
The error given is "The type initializer for 'Newtonsoft.Json.Utilities.JavaScriptUtils' threw an exception."
This happens with various versions of Newtonsoft.Json, including the latest (11.0.2) and going back as far as 7.0.1. Didn't have this error before but I have updated Xamarin Forms today (3.0.0.550146).
Exception info here: https://pastebin.com/GWPJdj6T
Line 81 is call to JsonConvert.DeserializeObject
public class RegisterResponse
{
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("message")]
public string Messsage { get; set; }
}
public static async Task<string> RequestAccessCode(string email) {
try {
using (var client = new HttpClient()) {
var response = await client.PostAsync(baseAddress + requestAccess, new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>("email", email.Trim())
}));
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<RegisterResponse>(responseContent);
return result.Messsage;
}
}
catch (Exception exception) {
return exception.FormatExceptionInfo(false);
}
}
Im developing a small Tcp Client Socket application in windows phone. Actually i have a text box, in that whatever the data received from a TCP server, should update continuously in UI text box control.
while (val)
{
result = Receive();
Dispatcher.BeginInvoke((Action)(() =>
{
txtOutput.Text += result;
}));
}
Here in above code, method receive() will receive string data and should update in textbox control but it is not happening,no data is updating to it.
Can any one suggest, how can i resolve this.
Just telling you what i have been advised, "avoid Dispatcher, CoreDispatcher, etc. There are always better solutions."
Below is the piece of code worked for me for both wp8 and wp8.1 WinRT app,
IProgress<object> progress = new Progress<object>(_ => UpdateTicker());
Task.Run(async () =>
{
while (val)
{
progress.Report(null);
}
});
where UpdateTicker() method contains your instructions, in this case...
public void UpdateTicker()
{
result = Receive();
txtOutput.Text += result;
}
Hope this helps...
Thanks for everyone, who given a valuable response for my post.
Hi Nishchith,
I tried your code, but it dint works for me
Here is my logic used to update textbox continuously with data received from TCP server.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using PhoneApp3.Resources;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using Windows.Phone.Networking;
using System.Threading.Tasks;
namespace PhoneApp3
{
public partial class MainPage : PhoneApplicationPage
{
Socket _socket = null;
static ManualResetEvent _clientDone = new ManualResetEvent(false);
const int TIMEOUT_MILLISECONDS = 1000;
const int MAX_BUFFER_SIZE = 2048;
const int ECHO_PORT = 9055; // The Echo protocol uses port 7 in this sample
const int QOTD_PORT = 49152; // The Quote of the Day (QOTD) protocol uses port 17 in this sample
string result = string.Empty;
public MainPage()
{
InitializeComponent();
}
private void btnEcho_Click(object sender, RoutedEventArgs e)
{
SocketClient client = new SocketClient();
Connect(txtRemoteHost.Text, ECHO_PORT);
//close();
}
public void Connect(string hostName, int portNumber)
{
DnsEndPoint hostEntry = new DnsEndPoint(hostName, portNumber);
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = hostEntry;
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
result = e.SocketError.ToString();
_clientDone.Set();
});
_clientDone.Reset();
Thread.Sleep(2000);
_socket.ConnectAsync(socketEventArg);
Thread.Sleep(5000);
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
bool val;
if (result == "Success")
{
val = true;
}
else
{
val = false;
}
IProgress<object> progress = new Progress<object>(_ => UpdateTicker());
Task.Run(async () =>
{
while (val)
{
progress.Report(null);
}
});
}
public void UpdateTicker()
{
result = Receive();
string[] strsplit = result.Split(' ');
txtOutput.Text = strsplit[1];
}
public string Receive()
{
string response = "Operation Timeout";
if (_socket != null)
{
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// Retrieve the data from the buffer
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
}
else
{
response = e.SocketError.ToString();
}
_clientDone.Set();
});
_clientDone.Reset();
Thread.Sleep(1000);
_socket.ReceiveAsync(socketEventArg);
Thread.Sleep(1000);
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
public void Close()
{
if (_socket != null)
{
_socket.Close();
}
}
}
}
I have a form on a webpage that I submit using the jquery form plugin. This form includes a file upload option. The MVC3 action that I post to returns JSON. Since the plugin falls back to using an iframe on older browsers you need to wrap your JSON with a
<textarea>JSON data...</textarea>
I tried changing the return type of the action to string and just appending the text area tags the the JSON object.ToString() but no go. How can I wrap my JSON result in a textarea when !Request.IsAjaxRequest()
Here is an example of me just trying to return the JSON as a string (which doesn't work)
[HttpPost]
public string CreateEntry(EntryCreateViewModel model)
{
if (!ModelState.IsValid)
{
return WrapInTextArea(!Request.IsAjaxRequest(), Json(new object[] { false, 0, this.RenderPartialViewToString("_EntryCreateFormPartial", model) }).ToString());
}
This works in modern browsers but I suspect (based on the docs) will fail in older browsers that use an iframe
[HttpPost]
public ActionResult CreateEntry(EntryCreateViewModel model)
{
if (!ModelState.IsValid)
{
return Json(new object[] {false, 0, this.RenderPartialViewToString("_EntryCreateFormPartial", model)});
}
To solve this I inherited from JsonResult and added the textarea there
using System;
using System.Web.Mvc;
using System.Web.Script.Serialization;
namespace TinyHouseMap.Web.Infrastructure.Results
{
public class JsonInIframeResult : JsonResult
{
public bool EncloseInTextArea
{
get;
set;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if ((JsonRequestBehavior == JsonRequestBehavior.DenyGet)
&& string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("JsonRequest GetNotAllowed");
}
var response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
var serializer = new JavaScriptSerializer();
string results;
if (EncloseInTextArea)
{
results = "<textarea>" + serializer.Serialize(Data) + "</textarea>";
}
else
{
results = serializer.Serialize(Data);
}
response.Write(results);
}
}
}
}
And then created a helper in my controller base class
protected JsonInIframeResult JsonInIframe(object data, string contentType, bool encloseInTextArea)
{
var result = new JsonInIframeResult {Data = data, ContentType = contentType, EncloseInTextArea = encloseInTextArea};
return result;
}