sonodan.
sonodan.
CC#
Created by sonodan. on 12/23/2022 in #help
❔ API External OAuth Not Triggering Challenge
Hi all, I have an API endpoint that challenges an external oauth provider scheme to redirect the user to approve access and return an access token. This endpoint works when I call the API endpoint directly. However, when I use a front-end button to trigger an HttpClient call to this endpoint, it hits the endpoint and passes over this statement, but it doesn't redirect to the external identity provider. Any insight why this might be happening? My front-end and backend are on different localhost ports.
[HttpGet]
[Route("login-reddit")]
[AllowAnonymous]
public async Task Login()
{
await HttpContext.ChallengeAsync(
RedditAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties()
{
RedirectUri = "https://localhost:7109/api/accounts/register"
});
}
[HttpGet]
[Route("login-reddit")]
[AllowAnonymous]
public async Task Login()
{
await HttpContext.ChallengeAsync(
RedditAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties()
{
RedirectUri = "https://localhost:7109/api/accounts/register"
});
}
2 replies
CC#
Created by sonodan. on 12/7/2022 in #help
❔ Authorize attribute automatically triggering oauth scheme
Hi all. I have a login endpoint that I want to call that will trigger my authenication scheme like so:
[HttpGet]
[Route("login")]
[AllowAnonymous]
public async Task Login()
{
await HttpContext.ChallengeAsync(
RedditAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties()
{
RedirectUri = "https://localhost:7109/api/Accounts/register"
});
}
[HttpGet]
[Route("login")]
[AllowAnonymous]
public async Task Login()
{
await HttpContext.ChallengeAsync(
RedditAuthenticationDefaults.AuthenticationScheme, new AuthenticationProperties()
{
RedirectUri = "https://localhost:7109/api/Accounts/register"
});
}
I also have another endpoint, register , which has an [Authorize] attribute. I want to test that visiting the Register controller before being authenticated returns an error code, but instead it automatically triggers a challenge to my auth provider, which isn't the intended behaviour I would like. I want users only to be able to authenticate using the login end point. Is there a way to override this behaviour?
[HttpGet]
[Route("register")]
[Authorize]
public async Task Register()
{
// controller logic
}
[HttpGet]
[Route("register")]
[Authorize]
public async Task Register()
{
// controller logic
}
2 replies
CC#
Created by sonodan. on 11/24/2022 in #help
✅ Authentication with Cookies
I'm playing around with cookies to get a better understanding. My code:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication("cookie")
.AddCookie("local");

var app = builder.Build();

app.UseAuthentication();

app.MapGet("/", () => "Hello World!");

app.MapGet("/login", async (HttpContext ctx) =>
{
var claims = new List<Claim>();
claims.Add(new Claim("usr", "daniel"));
var identity = new ClaimsIdentity(claims, "local");
var user = new ClaimsPrincipal(identity);
await ctx.SignInAsync("local", user);
});

app.MapGet("/user-info", (HttpContext ctx) =>
{
return ctx.User.FindFirstValue("usr") ?? "empty";
});

app.Run();
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication("cookie")
.AddCookie("local");

var app = builder.Build();

app.UseAuthentication();

app.MapGet("/", () => "Hello World!");

app.MapGet("/login", async (HttpContext ctx) =>
{
var claims = new List<Claim>();
claims.Add(new Claim("usr", "daniel"));
var identity = new ClaimsIdentity(claims, "local");
var user = new ClaimsPrincipal(identity);
await ctx.SignInAsync("local", user);
});

app.MapGet("/user-info", (HttpContext ctx) =>
{
return ctx.User.FindFirstValue("usr") ?? "empty";
});

app.Run();
Currently, the user-info endpoint returns "empty" after getting a cookie from the login endpoint. When I changed to AddCookie("cookie"), and change the ClaimsIdentity and Signin to "cookie", it returns a claim value. I was under the impression I could name the AddCookie scheme whatever I would like. Could someone please explain?
18 replies
CC#
Created by sonodan. on 10/25/2022 in #help
HttpGet API Endpoint Accepting Array Parameter
I have an endpoint for an HttpGet method:
[Route("fightIds")]
[HttpGet]
public async Task<IActionResult> GetPredictionsByFight([FromQuery] IEnumerable<int> fightIds)
{
var predictions = await _predictionService.GetPredictionsByFights(fightIds);

return new OkObjectResult(predictions);
}
[Route("fightIds")]
[HttpGet]
public async Task<IActionResult> GetPredictionsByFight([FromQuery] IEnumerable<int> fightIds)
{
var predictions = await _predictionService.GetPredictionsByFights(fightIds);

return new OkObjectResult(predictions);
}
Is it best practice to use [FromQuery] and accept the values as part of the URI? If so, what's the best way to build this request URI for my HttpClient? Do I need to manually concatenate a string, e.g. 'https://localhost:7109/api/Predictions/fightIds?fightIds=1&fightIds=2'? This feels like I'm doing something that is bad practice here. Or should my endpoint be accepting [FromBody] or some other way?
4 replies
CC#
Created by sonodan. on 10/21/2022 in #help
EF Core - Generic repository update method
I have a generic repository which contains my general CRUD operations interacting with my DbContext. I have an Update method which updates the Entity in the dbSet based on the new values. The TEntity is a class which has a property that depends on another custom class. When I call this function, all TEntity properties are updated except these navigation properties. Is there a way to generically add Include and take an argument of properties to include?
public void Update(TEntity entity)
{
_dbSet.Update(entity);
}
public void Update(TEntity entity)
{
_dbSet.Update(entity);
}
For extra context, I was able to do something similar on my Get methods, but unsure how this really would applied to update:
public async Task<IEnumerable<TEntity>> GetAsync(Expression<Func<TEntity, bool>>? filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>? orderBy = null, params string[] includes)
{
var query = _dbSet.AsQueryable();

query = includes.Aggregate(query, (current, include) => current.Include(include));

if (filter != null)
query = query.Where(filter);

var result = orderBy != null ? (await orderBy(query).ToListAsync()) : (await query.ToListAsync());

return result;
}
public async Task<IEnumerable<TEntity>> GetAsync(Expression<Func<TEntity, bool>>? filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>? orderBy = null, params string[] includes)
{
var query = _dbSet.AsQueryable();

query = includes.Aggregate(query, (current, include) => current.Include(include));

if (filter != null)
query = query.Where(filter);

var result = orderBy != null ? (await orderBy(query).ToListAsync()) : (await query.ToListAsync());

return result;
}
2 replies
CC#
Created by sonodan. on 10/18/2022 in #help
Structuring SQL database to accommodate models
I have the following models (simplified for demo):
public class Event
{
public int Id { get; set;}
public string Name { get; set;}
public IEnumerable<Fight> Fights { get; set;}
}

public class Fight
{
public int Id { get; set;}
public int EventId { get; set;}
// other unimportant properties
}
public class Event
{
public int Id { get; set;}
public string Name { get; set;}
public IEnumerable<Fight> Fights { get; set;}
}

public class Fight
{
public int Id { get; set;}
public int EventId { get; set;}
// other unimportant properties
}
I have set up two SQL tables: - Events (columns: Id (PK), Name) - Fights (columns: Id (PK), EventId(FK)) I have set the primary keys to be Identity in SQL, such that I leave the responsibility of creating the Ids to the database. I read Event and Fight data from an external API. So when I have these objects in memory (after API call), the Ids for each of the objects are null (0). Currently, I have to write the Events to the database and return the objects that are written, so I can fetch the respective EventId properties to then use LINQ to assign to the relevant Fight model. Then I can write the Fight model to the database. If I complete these database calls out of order (i.e. write Fight model to DB first), the DB write fails because the Fight model EventId isn't set. This feels to me like I've implemented a bad design approach, as this may not be obvious to other coders that the call order to the DB write is important (note this is only a personal project, so in reality it doesn't matter but I would like to understand a better approach). I've tried to search this on google, but I'm finding it hard to reduce my situation into a query that gets valuable information.
6 replies
CC#
Created by sonodan. on 10/9/2022 in #help
Using SQL db to create object ID or application?
I have an application where my records in my DB need to have unique IDs. Should I leave this responsibility to the SQL db to create them or should this be handled on the application side? If the former, if I insert a new record input the db and it auto-creates its ID, is the best practice to use output SQL command to read that ID value from the DB and attached it to my object in memory? If the latter, are there any best practice patterns to handle IDs that you recommend? Thanks in advance!
15 replies
CC#
Created by sonodan. on 10/3/2022 in #help
Http 400 Bad Request Response [Answered]
POST controller in WebAPI.
[Route("api/[controller]")]
[ApiController]
public class EventsController : ControllerBase
{
[HttpPost]
public async Task UpdateContacts(List<EventModel> events)
{
// Do things here

}
}
[Route("api/[controller]")]
[ApiController]
public class EventsController : ControllerBase
{
[HttpPost]
public async Task UpdateContacts(List<EventModel> events)
{
// Do things here

}
}
Service from the client that calls the Web API:
public async Task UpdateEvents(int userId, List<EventModel> events)
{
var contractResolver = new DefaultContractResolver()
{
NamingStrategy = new CamelCaseNamingStrategy()
};

var json = JsonConvert.SerializeObject(events, new JsonSerializerSettings
{
ContractResolver = contractResolver,
Formatting = Formatting.Indented
});

_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

var result = await _httpClient.PostAsJsonAsync($"api/events", json);
}
public async Task UpdateEvents(int userId, List<EventModel> events)
{
var contractResolver = new DefaultContractResolver()
{
NamingStrategy = new CamelCaseNamingStrategy()
};

var json = JsonConvert.SerializeObject(events, new JsonSerializerSettings
{
ContractResolver = contractResolver,
Formatting = Formatting.Indented
});

_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

var result = await _httpClient.PostAsJsonAsync($"api/events", json);
}
I've tried many things, including serializing the object to Json using Newtonsoft and just passing the object in for the HttpClient to serialize. I keep getting a 400 bad request response, and the content doesn't seem to provide any insight as to why that is. Note that I have provided the correct base URL to the httpClient as it works for my GET requests.
139 replies
CC#
Created by sonodan. on 8/30/2022 in #help
Searching a string for a substring containing operators
I'm trying to find how many times the string "*" occurs in a string I have. I've tried a few different things including backslashes, but I found a stackoverflow solution saying a string literal should work: var matches = response.Where(s => s.Contains(@""*"")).Count; I'm met with an error Operator * cannot be applied to operands of type 'string' and 'string'. What's the best practice here to accomplish this?
18 replies
CC#
Created by sonodan. on 8/27/2022 in #help
Dereference of a possibly null reference [Answered]
15 replies