MVC to WebApi calls losing session - asp.net

I am using MVC and WebApi in same project, not using Session in WebApi.
In MVC BaseController I have something along these line
protected const string HOME = "HOME";
protected SessionDataStore SessionDataStore
{
get
{
if ((Session[HOME] != null) && (Session[HOME] is SessionDataStore))
{
return (SessionDataStore)Session[HOME];
}
}
set
{
Session[HOME] = value;
}
}
public class SessionDataStore
{
public Request CurrentRequest { get; set; }
public Customer CurrentCustomer { get; set; }
public List<Salutation> Salutations { get; set; }
public WebServiceConfiguration CurrentConfiguration { get; set; }
public List<int> CurrentConfigurationIds { get; set; }
public List<int> CurrentAttributeIds { get; set; }
public SessionDataStore()
{
CurrentRequest = new Request();
CurrentCustomer = new Customer();
Salutations = new List<Salutation>()
{
new Salutation() { Id = 1, Name = "Mr", },
new Salutation() { Id = 2, Name = "Mrs", },
new Salutation() { Id = 3, Name = "Miss", },
new Salutation() { Id = 4, Name = "Ms", },
new Salutation() { Id = 5, Name = "Dr", },
new Salutation() { Id = 6, Name = "Prof", },
new Salutation() { Id = 7, Name = "Other", }
};
CurrentConfiguration = new WebServiceConfiguration();
CurrentConfigurationIds= new List<int>();
CurrentAttributeIds = new List<int>();
}
}
In my MVC project, I call the web API and update the Session object like this.
I initialise SessionDataStore in the index page to a new object
var client = new HttpClient(_handler);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync(string.Concat(GetBaseUrl().AbsoluteUri + "api/request/", requestId)).Result;
SessionDataStore.CurrentRequest = response.IsSuccessStatusCode ? response.Content.ReadAsAsync<Request>().Result : null;
The status code is Success but then I am losing the session.
Not sure why this is happening. I am using inProc session

Web API is REST-compliant, and REST is stateless. In other words, no session. You cannot access the session in a Web API action. If you need to interact with the session via an AJAX call, you will need to simply create an MVC Controller action to handle it instead of a Web API ApiController action.

If you didn't find the answer yet, this is how you can enable session usage inside web api request. You have to write the Application_PostAuthorizeRequest inside the Global.asax.cs like this:
protected void Application_PostAuthorizeRequest()
{
if(IsWebApiRequest())
HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
}
private bool IsWebApiRequest()
{
return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.Contains("/api/");
}

Related

Xamarin Essentials WebAuthenticator.AuthenticateAsync method doesn't return any result

I have added a WebAuthenticator.AuthenticateAsync method in my xamarin forms app with start up Url as "https://accounts.google.com/o/oauth2/auth"
and call back url as "myapp://"
I have also tried with call back url as "com.googleusercontent.apps.{clientId}:/oauth2redirect"
I am doing this to add google login in my xamarin forms app.
On this browser with available google accounts are been showing up and after successful completion of email authentication it returns to app but result is not returned from WebAuthenticator.AuthenticateAsync method.
On second time invocation of this method returns the first invocation result as cancelled by user and the browser opens again for second time email authentication.
But it works in ios.
I have added 3 classes
public class Auth0Client
{
private readonly OidcClient oidcClient;
public Auth0Client(Auth0ClientOptions options)
{
var discovery = new DiscoveryPolicy
{
ValidateEndpoints = false,
Authority = "https://accounts.google.com"
};
oidcClient = new OidcClient(new OidcClientOptions
{
Authority = $"https://accounts.google.com/o/oauth2/auth",
ClientId = options.ClientId,
Scope = options.Scope,
RedirectUri = options.RedirectUri,
Browser = options.Browser,
ProviderInformation = options.ProviderInformation,
Policy = new Policy
{
Discovery = discovery,
RequireAccessTokenHash = false
},
});
}
public IdentityModel.OidcClient.Browser.IBrowser Browser
{
get
{
return oidcClient.Options.Browser;
}
set
{
oidcClient.Options.Browser = value;
}
}
public async Task<LoginResult> LoginAsync()
{
return await oidcClient.LoginAsync();
}
}
public class Auth0ClientOptions
{
public Auth0ClientOptions()
{
}
public string Domain { get; set; }
public string ClientId { get; set; }
public string RedirectUri { get; set; }
public string Scope { get; set; }
public IBrowser Browser { get; set; }
public ProviderInformation ProviderInformation { get; set; }
}
public class WebBrowserAuthenticator : IBrowser
{
public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default)
{
try
{
WebAuthenticatorResult result = await WebAuthenticator.AuthenticateAsync(
new Uri(options.StartUrl),new Uri(options.EndUrl));
var url = new RequestUrl(options.EndUrl)
.Create(new Parameters(result.Properties));
return new BrowserResult
{
Response = url,
ResultType = BrowserResultType.Success
};
}
catch (Exception ex)
{
return new BrowserResult
{
ResultType = BrowserResultType.UserCancel,
ErrorDescription = "Login canceled by the user."
};
}
}
}
In view model we are creating authoclient
private async void NavigateToGoogleLogin(object obj)
{
string clientId = null;
string redirectUri = null;
switch (Device.RuntimePlatform)
{
case Device.iOS:
clientId = AppConstants.GoogleiOSClientId;
redirectUri = AppConstants.GoogleiOSRedirectUrl;
break;
case Device.Android:
clientId = AppConstants.GoogleAndroidClientId;
redirectUri = AppConstants.GoogleAndroidRedirectUrl;
break;
}
var auth0client = new Auth0Client(new Auth0ClientOptions()
{
Domain = "accounts.google.com/o/oauth2/auth",
ClientId = clientId,
RedirectUri = redirectUri,
Scope = AppConstants.GoogleScope,
Browser = new WebBrowserAuthenticator(),
ProviderInformation = new ProviderInformation
{
IssuerName = "accounts.google.com",
AuthorizeEndpoint = AppConstants.GoogleAuthorizeUrl,
TokenEndpoint = AppConstants.GoogleAccessTokenUrl,
UserInfoEndpoint = AppConstants.GoogleUserInfoUrl,
KeySet = new JsonWebKeySet(),
},
});
var loginResult = await auth0client.LoginAsync();
}
We are using below constants in authoclient object creation
internal static string GoogleScope = "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile";
internal static string GoogleAuthorizeUrl = "https://accounts.google.com/o/oauth2/auth";
internal static string GoogleAccessTokenUrl = "https://www.googleapis.com/oauth2/v4/token";
internal static string GoogleUserInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo";
Xamarin forms version:5.0.0.2012
Xamarin essentials: 1.7.3
Thanks in advance

Consuming web api with RestSharp basic authentication return null

I am trying to consume an endpoint with RestSharp with Basic authentication.
I followed the instructions on the documentation https://restsharp.dev/getting-started/getting-started.html
The request was successful but I think the request body was malformed.
How can I get this to work
internal BalanceInquiryResponse BalanceInquiryRest(BalanceInquiryRequest BalanceInquiryRequest, Settings Settings)
{
// BalanceInquiryResponse BalanceInquiryResponse = new BalanceInquiryResponse();
var client = new RestClient(Settings.BaseUrl + "All/Inquiry");
client.Authenticator = new HttpBasicAuthenticator(Settings.Username, Settings.Password);
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
request.AddJsonBody(new
{
Acc = BalanceInquiryRequest.Acc
});
IRestResponse response = client.Execute(request);
IRestResponse<BalanceInquiryResponse> res = client.Execute<BalanceInquiryResponse>(request);
if (response.IsSuccessful)
{
BalanceInquiryResponse = new BalanceInquiryResponse
{
responseInquiry = res.Data.responseInquiry,
ResponseDescription = res.Data.ResponseDescription,
ResponseMessage = res.Data.ResponseMessage
};
return BalanceInquiryResponse;
}
else
{
BalanceInquiryResponse = new BalanceInquiryResponse
{
ResponseDescription = responseses.ErrorMessage,
};
return BalanceInquiryResponse;
}
}
This is my response body
{
"responseMessage": "Successful",
"responseDescription": "Request Successful",
"responseInquiry": null
}
When I tried with postman I got
{
"ResponseMessage": "Successful",
"ResponseDescription": "Request Successful",
"response": {
"AvalBal": 586324.42,
"ReverAmt": 0,
"AccCurrency": "US "
}
}
IRestResponse<BalanceInquiryResponse> res = client.Execute<BalanceInquiryResponse>(request);
So there is a specific reason...you are putting BalanceInquiryResponse in the generic IRestResponse above.
With the above call, this should automatically hydrate the BalanceInquiryResponse object, and you shouldn't need to hand map.
Aka, you should ~not~ need this below code:
BalanceInquiryResponse = new BalanceInquiryResponse
{
responseInquiry = res.Data.responseInquiry,
ResponseDescription = res.Data.ResponseDescription,
ResponseMessage = res.Data.ResponseMessage
};
I think your issue is that your POCO object (BalanceInquiryResponse) should perfectly match the "structure" of the JSON.
Change your BalanceInquiryResponse to PERFECTLY match the json "properties".
and recognize you have a nested object.
I think it it would be:
public class ResponsePoco {
public double AvalBal { get; set; }
public int ReverAmt { get; set; }
public string AccCurrency { get; set; }
}
public class BalanceInquiryResponse{
public string ResponseMessage { get; set; }
public string ResponseDescription { get; set; }
public ResponsePoco response { get; set; }
}
Pay attention the to "ResponsePoco response"..note the variable name is LOWERCASE .. because...the json has a lowercase "response" in it.
I have called the (child) object "ResponsePoco" to highlight the difference between the object name and the variable name.
If you cannot "perfectly" match the Poco properties. you can use attributes to "massage" the discrepencies. As seen here:
https://www.newtonsoft.com/json/help/html/JsonPropertyName.htm
public class Videogame
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("release_date")]
public DateTime ReleaseDate { get; set; }
}

how to generate a Http Request for AAD?

so, I get the Access Token and I want to create a request...
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", accesToken);
HttpResponseMessage response = await httpClient.GetAsync("https://graph.microsoft.com/v1.0/users");
Also, the Problem may be on setting the scopes for the authentication...i set it to:
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
But I don't know if it gets all application permissions that I have (it is a deamon).
You can use this sample which will help you to create events with same client credential flow which you are using but you need to change some things here.
You need to first give the Calendar.ReadWrite permission in the Azure portal for your app.
You need to add the below code in the Program.cs
if (result != null)
{
var httpClient = new HttpClient();
var apiCaller = new ProtectedApiCallHelper(httpClient);
await apiCaller.CallWebAPIToPostEvent($"{config.ApiUrl}v1.0/users/{user obj id}/calendars/{calendar id}/events", result.AccessToken, Display);
}
Then you need to add the below classes in the protectedApiCallHelper.cs
public class Event
{
[JsonProperty("subject")]
public string Subject { get; set; }
[JsonProperty("body")]
public Body Body;
[JsonProperty("start")]
public TimeAndDate Start;
[JsonProperty("end")]
public TimeAndDate End;
[JsonProperty("location")]
public Location Location;
[JsonProperty("attendees")]
public List<Attendees> Attendees;
}
public class Body
{
[JsonProperty("contentType")]
public string ContentType { get; set; }
[JsonProperty("content")]
public string Content { get; set; }
}
public class TimeAndDate
{
[JsonProperty("dateTime")]
public string DateTime { get; set; }
[JsonProperty("timeZone")]
public string TimeZone { get; set; }
}
public class Location
{
[JsonProperty("displayName")]
public string DisplayName { get; set; }
}
public class Attendees
{
[JsonProperty("emailAddress")]
public EmailAddress EmailAddress;
[JsonProperty("type")]
public string Type;
}
public class EmailAddress
{
[JsonProperty("address")]
public string Address { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
In this same ProtectedApiCallHelper class you can create a post request and get the details by adding the below code
public async Task CallWebAPIToPostEvent(string webApiUrl, string accessToken, Action<JObject> processResult)
{
var defaultRequetHeaders = HttpClient.DefaultRequestHeaders;
if (defaultRequetHeaders.Accept == null || !defaultRequetHeaders.Accept.Any(m => m.MediaType == "application/json"))
{
HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
defaultRequetHeaders.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
var payload = new Event
{
Subject = "Let's go for lunch",
Body = new Body
{
ContentType = "HTML",
Content = "Does mid month work for you?"
},
Start = new TimeAndDate
{
DateTime = "2019-03-15T12:00:00",
TimeZone = "Pacific Standard Time"
},
End = new TimeAndDate
{
DateTime = "2019-03-15T14:00:00",
TimeZone = "Pacific Standard Time"
},
Location = new Location
{
DisplayName = "Harry's Bar"
},
Attendees = new List<Attendees>
{
new Attendees
{
EmailAddress = new EmailAddress
{
Address = "Shiva#nishantsingh.live",
Name = "Shiva"
},
Type = "required"
}
}
};
// Serialize our concrete class into a JSON String
var stringPayload = await Task.Run(() => JsonConvert.SerializeObject(payload));
// Wrap our JSON inside a StringContent which then can be used by the HttpClient class
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");
HttpResponseMessage response = await HttpClient.PostAsync(webApiUrl, httpContent);
if (response.Content != null)
{
var responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}
}
This will help you create the event with these details.

Authorize Attribute User / Roles

I am new with authorization and security to applications. I'm building upon my angularjs and web api app that uses Owin and AspNet.Identity.EntityFramework. I've been able to get the authorization working to force a user to either register / log in to the app. Now I'm looking on how to add more specific access such as a an admin role or specific user to look at more sensitive data. I've started with the [Authorize] attribute. Which forced the security. Then I added [Authorize(User="tbryant")] which didnt allow other users and even the user tbryant to log in. There is a user name in the AspNetUsers table of tbryant.
Here is my sample data from my api controller:
[RoutePrefix("api/Orders")]
public class OrdersController : ApiController
{
[Authorize(Users="tbryant")]
[Route("")]
public IHttpActionResult Get()
{
return Ok(Order.CreateOrders());
}
}
public class Order
{
public int OrderID { get; set; }
public string CustomerName { get; set; }
public string ShipperCity { get; set; }
public Boolean IsShipped { get; set; }
public static List<Order> CreateOrders()
{
List<Order> OrderList = new List<Order>
{
new Order {OrderID = 10248, CustomerName = "Tee Joudeh", ShipperCity = "Cleveland", IsShipped = true },
new Order {OrderID = 10249, CustomerName = "Ahmad Hasan", ShipperCity = "Columbus", IsShipped = false},
new Order {OrderID = 10250,CustomerName = "Thomas Yaser", ShipperCity = "Detroit", IsShipped = false },
new Order {OrderID = 10251,CustomerName = "Lena Jones", ShipperCity = "Ann Arbor", IsShipped = false},
new Order {OrderID = 10252,CustomerName = "Yasmeen Rami", ShipperCity = "Bamberg", IsShipped = true}
};
return OrderList;
}
}
Make sure the "user.Identity.Name" in HttpContext is equal to "tbryant".
Here is how Authorize attribute works.
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}
if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
{
return false;
}
return true;
}

Formatting JSON in ASP.NET MVC

I want to return a JSON from ASP.NET MVC ActionResult type method that looks something like this:
{
success: true,
users: [
{id: 1, FileName: 'Text22'},
{id: 2, FileName: 'Text23'}
]
}
How would I format it? Right now I have something like this
Return Json(New With {Key .success = "true", Key .users = responseJsonString}, JsonRequestBehavior.AllowGet)
Edit: I am using VB.NET but answers in C# are fine too.
I prefer using ViewModels, rather than manually constructing complex JSON responses. It ensures consistency against all methods that return the data, and is easier to work with strongly typed properties IMHO.
public class Response
{
public bool Success { get; set; }
public IEnumerable<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
and then just:
Response response = new Response();
response.Success = true;
// populate the rest of the data
return Json(response);
This also has the advantage of letting you use a base class for every response, if there's common data like a success status, or error messages.
public class ResponseBase
{
public bool Success { get; set; }
public string Message { get; set; }
}
public class UserResponse : ResponseBase
{
IENumerable<User> Users { get; set }
}
Now, if you have an error:
return Json(new ResponseBase() { Success = false, Message = "your error" });
or if it succeeds
return Json(new UserResponse() { Success = true, Users = users });
If you want to manually craft the JSON, then just:
return Json(new { success = true, users = new[] { new { id = 1, Name = "Alice"}, new { id = 2, Name = "Bob"} } });
in C#
return Json(new
{
success = true,
users = new[]
{
new {id = 1, FileName = "Text22"}, new {id = 2, FileName = "Text23"}
}
}, JsonRequestBehavior.AllowGet);
returns
{"success":true,"users":[{"id":1,"FileName":"Text22"},{"id":2,"FileName":"Text23"}]}

Resources