Why HttpContext.Session.GetString returns null? - asp.net

This is my session save and fetch method:
[HttpPost]
[Route("save-to-session")]
public IActionResult SaveToSession(string id)
{
HttpContext.Session.SetString("user", id);
return Content(id);
}
[HttpGet]
[Route("fetch-from-session")]
public IActionResult FetchFromSession()
{
string name = HttpContext.Session.GetString("user");
return Content(name);
}
I'm using Sql Server Cache:
services.AddDistributedSqlServerCache(options => {
options.ConnectionString = Configuration.GetConnectionString("TestMEApiContext");
options.SchemaName = "dbo";
options.TableName = "Session";
});
services.AddSession(options => {
options.Cookie.Name = ".Session";
options.IdleTimeout = TimeSpan.FromMinutes(3000);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
and the data is saved to the database but when i try to fetch it always returns null.
This is how i try to fetch it in my react code:
fetch(`https://localhost:44369/api/users/fetch-from-session`, { method: 'GET', credentials: 'include', mode: 'cors' }).then(function (body) {
return body.text();
}).then((response) => {
console.log("My response")
console.log(response) // <-THIS IS NULL
});
And this is how i try to save it but save works:
await this.getUserId().then(async function (userId) {
fetch(`https://localhost:44369/api/users/save-to-session?id=${userId}`, {
method: 'POST',
mode: 'cors',
credentials: 'include'
});
})

Related

Angular - Post request failing to download pdf file

I am trying to do a POST request to download a pdf file from the sever. The error I get is message: "Http failure during parsing". I'm not sure why it would work for a GET request but not for a POST request or I am missing something.
this.httpClient.post(url, {
responseType: 'blob' as 'json',
observe: 'response'
})
.pipe(take(1))
.subscribe((data:HttpResponse<Blob>) => {
const blob = new Blob([data.body], { type: 'application/pdf' });
saveAs(blob, 'test.pdf');
});
However if I do a GET request, it seems to work.
this.httpClient.get<Blob>(url,
{
observe: 'response',
responseType: (('blob') as any) as 'json'
})
.pipe(take(1))
.subscribe(
(response: HttpResponse<Blob>) => {
const blob = new Blob([response.body], { type: mediaType });
saveAs(blob, 'Report.pdf');
},
(error: any) => {
console.error(error);
}
);
Server
[HttpPost]
[Route("download/{id}")]
public IHttpActionResult DownloadPdf()
{
var buffer = _test.RenderDrawing();
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(buffer)
};
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = $"Test.pdf"
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return ResponseMessage(result);
}
In you post request, you are defining types differently. try something like this:
this.httpClient.post(url, {
responseType: 'blob',
observe: 'response'
})
.pipe(take(1))
.subscribe((data:HttpResponse<Blob>) => {
const blob = new Blob([data.body], { type: 'application/pdf' });
saveAs(blob, 'test.pdf');
});

How to return two variables from ClientRequest?

I made http request (Class: ClientRequest) and I need to return two variables from my "login method" via promise.
function login(name, pass,server) {
return new Promise((resolve, reject) => {
const request = net.request({
method: 'GET',
url: server+'/names.nsf?Login&Username=' + name + '&Password=' + pass,
useSessionCookies: true,
redirect: 'follow'
}
)
var first
var second
///first
request.on('response', (response) => {
...
first = response.statusCode
})
///second
request.on('redirect', (statusCode, method, redirectUrl) => {
...
second = redirectUrl
})
resolve([first, second])
request.end()
});
}
And I am using it in this way:
ipcMain.on('loginbackend', async (event, arg) => {
try {
const loginInfo = await login(arg.name, arg.pass,arg.server)
event.returnValue = loginInfo
}
catch (error) {
console.error('ERROR:');
console.error(error);
}
});
I can return var putting resolve() into request.on method, but I need return both vars from both request.on. It seems request.on is asynchronize, how can I do that?
You should return your variables when end event of response is emited
function login(name, pass, server) {
return new Promise((resolve, reject) => {
const request = net.request({
method: 'GET',
url: server + '/names.nsf?Login&Username=' + name + '&Password=' + pass,
useSessionCookies: true,
redirect: 'follow'
}
)
var first
var second
///first
request.on('response', (response) => {
...
first = response.statusCode
response.on('end', () => {
resolve([first, second]);
});
})
///second
request.on('redirect', (statusCode, method, redirectUrl) => {
...
second = redirectUrl
})
request.end()
});
}

Microsoft Teams Tab with MSAL sign in

I've been working on getting a custom tab working in MS teams using MSAL. I've been following the example here: https://github.com/nmetulev/teams-msal and I can generate a token. I then try to forward this token to my API, where I build a security claim and call SignInAsync() to persist the cookie.
This then gets stored, and I forward to my standard page, but this does not page auth (I get unauthorized). Is there something I'm missing that I need to be doing?
Auth Page
const signIn = () => {
msalApp.acquireTokenRedirect(authenticationParameters);
}
const handleSignedIn = () => {
microsoftTeams.initialize();
microsoftTeams.authentication.notifySuccess();
}
const handleSignedOut = (error) => {
microsoftTeams.initialize();
microsoftTeams.authentication.notifyFailure(error);
}
const handleErrorReceived = (authError, accountState) => {
console.log(authError, accountState);
handleSignedOut({authError});
}
const handleTokenReceived = (response) => {
console.log(response);
handleSignedIn();
}
// MAIN
const msalApp = new Msal.UserAgentApplication(msalConfig);
msalApp.handleRedirectCallback((response) => handleTokenReceived(response), (error, state) => handleErrorReceived(error, state));
microsoftTeams.initialize();
microsoftTeams.getContext((context) => {
authenticationParameters = {
scopes: scopes,
loginHint: context.loginHint
};
setTimeout(() => {
attemptSilentSignIn().then(success => {
if (success) {
handleSignedIn();
} else {
signIn();
}
});
},
4000);
});
Sign In Page:
const attemptSilentSignIn = () => {
renderLoading();
if (msalApp.getAccount()) {
msalApp.acquireTokenSilent({ scopes }).then((response) => {
if (response && response.accessToken) {
handleSignedIn(response.accessToken);
} else {
handleSignedOut();
}
}, () => {
handleSignedOut();
})
} else {
handleSignedOut();
}
}
const signIn = () => {
renderLoading();
microsoftTeams.initialize(() => {
microsoftTeams.authentication.authenticate({
url: window.location.origin + "/resources/TeamsAuthFlow.html",
successCallback: () => attemptSilentSignIn(),
failureCallback: (error) => renderError(error)
});
});
}
const handleSignedIn = (accessToken) => {
microsoftTeams.initialize();
microsoftTeams.getContext((context) => {
var tenant = $("<input>").attr("id", "TenantId").attr("name", "TenantId").val(context.tid);
var token = $("<input>").attr("id", "AuthToken").attr("name", "AuthToken").val(accessToken);
var form = $("<form>").css("display", "none").attr("id", "target").attr("method", "POST").attr("action", "/api/TeamsTabSignIn").append(tenant).append(token).submit();
$("body").append(form);
$("#target").submit();
});
}
const handleSignedOut = () => {
renderSignedOutView();
}
// MAIN
let app = document.querySelector('.app');
const msalApp = new Msal.UserAgentApplication(msalConfig);
attemptSilentSignIn();
let authenticationParameters = null;
const handleErrorReceived = (authError, accountState) => {
console.log(authError, accountState);
handleSignedOut({ authError });
}
const handleTokenReceived = (response) => {
console.log(response);
handleSignedIn();
}
API Call
TenantId = Context.Request.Form["TenantId"];
AuthToken = Context.Request.Form["AuthToken"];
var principal = await _authHelper.SetPlatformUser(TenantId, AuthToken);
if (principal is ClaimsPrincipal cp)
{
await Context.SignInAsync("Cookies", cp, new AuthenticationProperties { IsPersistent = true });
Response.Redirect("/app/teamspage/Ticket");
}

webapi 404 not found when calling from react with post action

I have the following controller action
[HttpPost]
[Route("api/Tenant/SetTenantActive")]
public async Task<IHttpActionResult> SetTenantActive(string tenantid)
{
var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
var allTenants = await tenantStore.Query().Where(x => x.TenantDomainUrl != null).ToListAsync();
foreach(Tenant ten in allTenants)
{
ten.Active = false;
await tenantStore.UpdateAsync(ten);
}
var tenant = await tenantStore.Query().FirstOrDefaultAsync(x => x.Id == tenantid);
if (tenant == null)
{
return NotFound();
}
tenant.Active = true;
var result = await tenantStore.UpdateAsync(tenant);
return Ok(result);
}
And my react code:
import React, { Component } from 'react';
import { Table, Radio} from 'antd';
import { adalApiFetch } from '../../adalConfig';
import Notification from '../../components/notification';
class ListTenants extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
fetchData = () => {
adalApiFetch(fetch, "/Tenant", {})
.then(response => response.json())
.then(responseJson => {
if (!this.isCancelled) {
const results= responseJson.map(row => ({
key: row.ClientId,
ClientId: row.ClientId,
ClientSecret: row.ClientSecret,
Id: row.Id,
SiteCollectionTestUrl: row.SiteCollectionTestUrl,
TenantDomainUrl: row.TenantDomainUrl
}))
this.setState({ data: results });
}
})
.catch(error => {
console.error(error);
});
};
componentDidMount(){
this.fetchData();
}
render() {
const columns = [
{
title: 'Client Id',
dataIndex: 'ClientId',
key: 'ClientId'
},
{
title: 'Site Collection TestUrl',
dataIndex: 'SiteCollectionTestUrl',
key: 'SiteCollectionTestUrl',
},
{
title: 'Tenant DomainUrl',
dataIndex: 'TenantDomainUrl',
key: 'TenantDomainUrl',
}
];
// rowSelection object indicates the need for row selection
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
if(selectedRows[0].key != undefined){
console.log(selectedRows[0].key);
const options = {
method: 'post',
body: {tenantid:selectedRows[0].key},
};
adalApiFetch(fetch, "/Tenant/SetTenantActive", options)
.then(response =>{
if(response.status === 200){
Notification(
'success',
'Tenant created',
''
);
}else{
throw "error";
}
})
.catch(error => {
Notification(
'error',
'Tenant not created',
error
);
console.error(error);
});
}
},
getCheckboxProps: record => ({
type: Radio
}),
};
return (
<Table rowSelection={rowSelection} columns={columns} dataSource={this.state.data} />
);
}
}
export default ListTenants;
focus only on the onchange event,
And the screenshot:
And it looks like the request gets to the webapi (I attached the debugger)
Update:
Basically If I dont put FromBody I need to send the parameter via querystring.
However if I put from Body and I send the parameter in the body, its received null on the webapi
Add [FromBody] before your input parameter in your action method like this:
public async Task<IHttpActionResult> SetTenantActive([FromBody] string tenantid)
Then, convert your selected row key into string
const options = {
method: 'post',
body: { tenantid : selectedRows[0].key.toString() }
};

Observable from 2 promises

I think my solution is in this question but I can't get it to work Promise.all behavior with RxJS Observables?
I'm trying to return an observable on two promises via forkJoin.
One promise gets an ID from the server and another processes a file to generate a thumbnail.
export function createSceneFromFile(action$) {
return action$.ofType(CREATE_SCENE_FROM_FILE)
.mergeMap(({locationId,file}) =>
createSceneThumb(locationId,file)
.map((res,preview) => {
console.log(res,preview)
if (res.error) {
return { type: CREATE_SCENE_FAILED, payload: res.message }
} else {
return {type: CREATE_SCENE_SUCCESS, payload: {...res.payload,preview} }
}
})
.catch(err => { return { type: CREATE_SCENE_FAILED, message: err } })
)
}
function createSceneThumb(locationId,file){
const request = fetch(`${API_URL}/location/${locationId}/createscene/${file.name}/`, {
method: 'get',
credentials: 'include',
}).then(res => res.json())
const thumb = fileToScenePreview(file)
return Observable.forkJoin(request,thumb)
}
export function fileToScenePreview(file){
return new Promise((resolve,reject)=>{
getFileThumb(file).then((canvas)=> {
canvas.toBlob((blob) => {
blob.lastModifiedDate = new Date()
blob.name = 'scenepreview_' + file.name + '.png'
const uploader = new S3Upload({
getSignedUrl: getSignedUrl,
uploadRequestHeaders: {'x-amz-acl': 'public-read'},
contentType: 'image/png',
scrubFilename: (filename) => filename.replace(/[^\w\d_\-.]+/ig, ''),
contentDisposition: 'auto',
s3path: 'assets/',
onError:()=>reject,
onFinishS3Put: ()=>resolve(blob.name),
})
uploader.uploadFile(blob)
})
})
})
}
But i never get a response.
Is this the right way of going about it?

Resources