Blazored.LocalStorage.ILocalStorageService.GetItemAsync<!0>(string)) - jwt

I am new for .NET6 and I have created blazor WASM application in .NET 6.its authentication part is JWT authentication. when I am going to store the token into local storage following error is occurred.
blazor.webassembly.js:1 System.AggregateException: One or more errors occurred. (Method not found: System.Threading.Tasks.ValueTask1<!!0> Blazored.LocalStorage.ILocalStorageService.GetItemAsync<!0>(string)) ---> System.MissingMethodException: Method not found: System.Threading.Tasks.ValueTask1<!!0>
Blazored.LocalStorage.ILocalStorageService.GetItemAsync<!0>(string)
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[d__8](d__8& stateMachine) in System.Private.CoreLib.dll:token 0x600454a+0x28
at Infrastructure.Manager.Preferences.ClientPreferenceManager.GetPreference() in Infrastructure.dll:token 0x600004d+0xc
at BlSls.Client.Program.Main(String[] args) in BlSls\Client\Program.cs:line 36
--- End of inner exception stack trace ---
my program.cs
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args).AddRootComponents().AddClientServices();
var host = builder.Build();
var storageService = host.Services.GetRequiredService<ClientPreferenceManager>();
if (storageService != null)
{
CultureInfo culture;
var preference = await storageService.GetPreference() as ClientPreference;
}
builder.Services.AddMudServices();
builder.Services.AddTransient<ILocalItemStore,LocalItemStore>();
builder.Services.AddSingleton<IDataConnect, DataConnect>();
builder.Services.AddScoped<Service.InterData>();
await builder.Build().RunAsync();
}
ILocalStorageService.cs
public interface ILocalStorageService
{
event EventHandler<ChangingEventArgs> Changing;
event EventHandler<ChangedEventArgs> Changed;
ValueTask ClearAsync();
ValueTask<bool> ContainKeyAsync(string key);
ValueTask<string> GetItemAsStringAsync(string key);
ValueTask<T> GetItemAsync<T>(string key);
ValueTask<string> KeyAsync(int index);
ValueTask<int> LengthAsync();
ValueTask RemoveItemAsync(string key);
ValueTask SetItemAsync<T>(string key, T data);
}
required DI in import.razor
#inject BL10StateProvider _stateProvider
#inject IAuthenticationManager _authenticationManager
login.razor
<div class="d-block">
<EditForm Model="#_tokenModel" OnValidSubmit="SubmitAsync">
<DataAnnotationsValidator />
<div class="#(f ? "invalid-box":"user-box")">
<InputText placeholder="Username" #bind-Value="_tokenModel.UserName" />
<ValidationMessage For="() => _tokenModel.UserName" />
#*<label class="body-default">Email</label>*#
</div>
<div class="#(f ? "invalid-box":"user-box")">
<InputText type="password" placeholder="Password" #bind-Value="_tokenModel.Password" />
<ValidationMessage For="() => _tokenModel.Password" />
#*<label class="body-default">Password</label>*#
</div>
<div>
<button type="submit" class="btn-block login-btn button-text"> Sign In</button>
</div>
</EditForm>
</div>
login.razor.cs
public partial class Login
{
bool f = false;
private TokenRequest _tokenModel = new();
protected override async Task OnInitializedAsync()
{
var state = await _stateProvider.GetAuthenticationStateAsync();
if (state != new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())))
{
_navigationManager.NavigateTo("/login");
}
await Task.FromResult(0);
}
private async Task SubmitAsync()
{
var result = await _authenticationManager.Login(_tokenModel);
if (result.Succeeded)
{
f = false;
_navigationManager.NavigateTo("/CompanySelection", true);
}
else
{
_tokenModel.Messaage = "UserName Or Password Incorrect";
f = true;
}
}
}
BL10StateProvider.cs
public class BL10StateProvider {
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var savedToken = await _localStorage.GetItemAsync<string>(StorageConstants.Local.AuthToken);
if (string.IsNullOrWhiteSpace(savedToken))
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", savedToken);
var state = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(GetClaimsFromJwt(savedToken), "jwt")));
AuthenticationStateUser = state.User;
return state;
}
}
AuthenticationManager.cs
public class AuthenticationManager{
public async Task<IResult> Login(TokenRequest model)
{
HttpResponseMessage response=null;
try
{
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("POST"), TokenEndpoints.Authenticate))
{
request.Headers.TryAddWithoutValidation("Timestamp", DateTime.Now.Ticks.ToString());
request.Content = JsonContent.Create(model);
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
response = await httpClient.SendAsync(request);
}
}
}
catch (Exception exp)
{
model.Messaage = "Login Falied";
model.IsTokenRequestFailed = true;
return await Result.FailAsync("Server Or API Host Not found");
}
//HttpRequestMessage req = new HttpRequestMessage();
//req.Method = HttpMethod.Post;
//req.RequestUri = TokenEndpoints.Authenticate;
//req.
////var response = await _httpClient.PostAsJsonAsync(TokenEndpoints.Authenticate, model);
// var response = await _httpClient.PostAsJsonAsync()
string responseBody = await response.Content.ReadAsStringAsync();
TokenResponse tokenRequest = JsonConvert.DeserializeObject<TokenResponse>(responseBody);
//var result = await response.ToResult<TokenResponse>();
if (tokenRequest.IsSuccess)
{
model.IsTokenRequestFailed = false;
model.Messaage = "Login Successful";
var token = tokenRequest.Token;
var refreshToken = tokenRequest.RefreshToken;
var userImageURL = tokenRequest.UserImageURL;
await _localStorage.SetItemAsync(StorageConstants.Local.AuthToken, token);
await _localStorage.SetItemAsync(StorageConstants.Local.RefreshToken, refreshToken);
if (!string.IsNullOrEmpty(userImageURL))
{
await _localStorage.SetItemAsync(StorageConstants.Local.UserImageURL, userImageURL);
}
((BL10StateProvider)this._authenticationStateProvider).MarkUserAsAuthenticated(model.UserName);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
return await Result.SuccessAsync();
}
else
{
model.Messaage = "Login Falied";
model.IsTokenRequestFailed = true ;
return await Result.FailAsync(tokenRequest.Messages);
}
}
}
please help me to solve this issue using above code sample.

When you are in Main(), before the .RunAsync(), the JavaScript is not yet loaded.
The error is in this line:
var preference = await storageService.GetPreference() as ClientPreference;
Whatever logic you have around this has to be executed later.
One possible place is in the App component, in OnAfterRenderAsync(true):
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var preference = await storageService.GetPreference() as ClientPreference;
...
}
}
But be aware that you first page may already be Initializing and Rendering before you have set that preference.

Related

I am using c# services and controllers with mongodb , facing issue in patch request I can patch using JsonPatchDocument but cannot save to mongo db

I am using MongoDB. I can post put and delete also get, can patch using JsonPatchDocument but face issue when trying to update in db.
Last Methods in UserService and UserController, which I want make for patch using JsonPatchDocument
This is my appsetting.json file
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"HealthCareDatabase": {
"ConnectionString": "mongodb://localhost:27017",
"DatabaseName": "HealthApp",
"UserCollectionName":"User",
"JobCollectionName":"Jobs",
"JobApplicationCollectionName":"jobApplications",
"EducationCollectionName":"Education",
"ExperienceCollectionName":"Experience",
"TestCollectionName":"Test"
}
}
UserServices.cs
using backend.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using Microsoft.AspNetCore.JsonPatch;
namespace backend.Services;
public class UserService :ControllerBase
{
private readonly IMongoCollection<User> _userCollection;
public UserService(
IOptions<HealthCareDbSettings> HealthCareDbSettings)
{
var mongoClient = new MongoClient(
HealthCareDbSettings.Value.ConnectionString);
var mongoDatabase = mongoClient.GetDatabase(
HealthCareDbSettings.Value.DatabaseName);
_userCollection = mongoDatabase.GetCollection<User>(
HealthCareDbSettings.Value.UserCollectionName);
}
// User Services are down there
public async Task<List<User>> GetAsync() =>
await _userCollection.Find(_ => true).ToListAsync();
public async Task<User?> GetAsync(string id) =>
await _userCollection.Find(user => user.Id == id).FirstOrDefaultAsync();
public User Login(string email, string password)
{
var user = _userCollection.Find(user => user.Email == email ).FirstOrDefault();
bool isPasswordValid = BCrypt.Net.BCrypt.Verify(password,user.Password);
if (isPasswordValid)
{
return user;
}
else{
return null;
}
}
public async Task CreateUser(User newUser) =>
await _userCollection.InsertOneAsync(newUser);
public async Task UpdateUser(string id,User user) =>
await _userCollection.ReplaceOneAsync(user => user.Id == id,user);
// This method has error
public async Task<User> updateUser(string id, JsonPatchDocument<User> patchDoc) {
var fromDb = await _userCollection.Find(user => user.Id == id).FirstOrDefaultAsync();
var filter = _userCollection.Find(user => user.Id == id).FirstOrDefaultAsync();
patchDoc.ApplyTo(fromDb,ModelState);
_userCollection.UpdateOne(filter,fromDb);
var user = await _userCollection.Find(user => user.Id == id).FirstOrDefaultAsync();
return user;
}
}
UserController.cs
using Microsoft.AspNetCore.Mvc;
using backend.Services;
using backend.Models;
using Microsoft.AspNetCore.JsonPatch;
namespace backend.Controllers;
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly UserService _userService;
public UserController(UserService userservice)
{
_userService = userservice;
}
public string err = "Invalid Credentials";
[HttpGet]
public async Task<List<User>> Get() =>
await _userService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<User>> Get(string id)
{
var user = await _userService.GetAsync(id);
if(user is null){
return NotFound();
}
return user;
}
[HttpPost("Login")]
public User userLogin([FromBody] Login login)
{
User usr = _userService.Login(login.email,login.password);
if(usr != null){
return usr;
}else {
return null;
}
}
// Creating New User
[HttpPost]
public async Task<IActionResult> Post(User newUser)
{
var usr = newUser;
var hashed = BCrypt.Net.BCrypt.HashPassword(newUser.Password);
usr.Password = hashed;
await _userService.CreateUser(usr);
return CreatedAtAction(nameof(Get), new { id = usr.Id }, usr);
}
//Update User
// [HttpPatch("up/{id:length(24)}")]
// public Task<User> update(string id,[FromBody] JsonPatchDocument<User> patchDoc)
// {
// var usr = _userService.GetAsync(id);
// return _userService.updateUser(id,patchDoc);
// }
}

SSE "data" field not being received by Dart http.client

I'm building a Flutter app that receives SSE from a server and translates them to specific notifications. The server is a Spring Boot app returning events containing "event:" and "data:" fields:
public void pushNotification(String username, PushEvent event) {
var emitter = emitters.get(username);
if (emitter == null) {
return;
}
try {
emitter.send(event.toSseEvent());
} catch (IOException e) {
log.debug("Could not send event for user " + username);
emitters.remove(username);
}
}
public class PushEvent {
private String type;
private Map<String, Object> body;
public SseEmitter.SseEventBuilder toSseEvent() {
return SseEmitter.event().name(type).data(body);
}
}
On the Flutter app, I use the Dart http package to open a Stream and receive the events:
Future<void> subscribe() async {
if (!_userModel.hasAuthentication()) {
return;
}
var user = _userModel.user as AuthenticatedUser;
var username = user.username;
var token = _userModel.getToken();
var uri = Uri.https(ApiUtils.API_BASE, '/api/push/subscribe/$username');
try {
var client = http.Client();
_client = client;
var request = new http.Request("GET", uri);
request.headers["Accept"] = "text/event-stream";
request.headers["Cache-Control"] = "no-cache";
request.headers["Authorization"] = token;
var response = await client.send(request);
if (response.statusCode == 200) {
_isSubscribed = true;
response.stream.toStringStream().forEach((value) {
var event = ServerEvent.parse(value);
_handleEvents(event);
}).onError((error, stackTrace) {
log.info("Connection closed");
log.info(error);
log.info(stackTrace);
unsubscribe();
}).whenComplete(() {
log.info("Connection completed");
unsubscribe();
subscribe();
});
} else {
_isSubscribed = false;
}
notifyListeners();
} catch (e) {
unsubscribe();
log.warning("Could not subscribe to notifications");
log.warning(e);
}
}
However, when I receive an event containing data from the server, the data does not show on the log:
I/flutter (14779): event:FRIEND_REQUEST
I/flutter (14779): data:
I am certain the data is being sent by the server since the React app on the same domain decodes the SSE and shows the notifications as intended:
const subscribePush = () => {
const username = sessionStorage.getItem('loggedUsername');
const token = sessionStorage.getItem('token');
var es = new EventSourcePolyfill(
'/api/push/subscribe/' + username,
{
headers: {
"Authorization": token,
}
}
);
es.onerror = () => es.close();
es.addEventListener("FRIEND_REQUEST", e => handleFriendRequestEvent(e));
es.addEventListener("FRIEND_ACCEPT", e => handleFriendAcceptEvent(e));
}
const handleFriendRequestEvent = function (event) {
const username = sessionStorage.getItem("loggedUsername");
const data = JSON.parse(event.data);
const source = data.source;
if (source !== username) {
var note = `${source} solicitou sua amizade!`;
var newNotifs = notifications.concat(note);
setNotifications(newNotifs);
setNewNotifications(newNotifications + 1);
}
}
Could something be missing from the request on the Flutter app, or is it possibly a bug?
Your implementation looks strangely similar to this one:
https://github.com/stevenroose/dart-eventsource
Take a look at the client implementation and how the response in decoded using the decoder.dart file.

How to create a CDN server in dotnet core using MongoDB GridFS and AngularJs

We want to create a decoupled file server named CDN in .net core using MongoDB GridFS and angular js.
From various sources I tried my best to solve the issue.
And finally we done this.
I used Visual Studio 2017 and .NETCore 1.1
To do so I follow the followings:
1. Write Code in MongoDB GridFS
create an interface like
public interface IGridFsRepository : IDisposable
{
Task<string> UploadAsync(IFormFile file);
Task<bool> AnyAsync(ObjectId id);
Task<bool> AnyAsync(string fileName);
Task DeleteAsync(string fileName);
Task DeleteAsync(ObjectId id);
Task<GridFSDownloadStream<ObjectId>> DownloadAsync(string fileName);
Task<GridFSDownloadStream<ObjectId>> DownloadAsync(ObjectId id);
object GetAllFilesByContentType(string contentType, int skip, int
take);
object GetAllFiles(int skip, int take);
}
then create MongoDbCdnContext:
public abstract class MongoDbCdnContext
{
public IGridFSBucket GridFsBucket {get;}
protected MongoDbCdnContext(string connectionStringName)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var connectionString =
config.GetConnectionString(connectionStringName);
var connection = new MongoUrl(connectionString);
var settings = MongoClientSettings.FromUrl(connection);
//#if DEBUG
// settings.ClusterConfigurator = builder =>
builder.Subscribe<CommandStartedEvent>(started =>
// {
// Debug.Write(started.Command);
// });
//#endif
var client = new MongoClient(settings);
var database = client.GetDatabase(connection.DatabaseName);
GridFsBucket = new GridFSBucket(database);
}
}
then implement it:
public class GridFsRepository : MongoDbCdnContext,
IGridFsRepository
{
public GridFsRepository() : base("MongoCdn")
{
}
public async Task<string> UploadAsync(IFormFile file)
{
var options = new GridFSUploadOptions
{
Metadata = new BsonDocument("contentType", file.ContentType)
};
using (var reader = new
StreamReader((Stream)file.OpenReadStream()))
{
var stream = reader.BaseStream;
var fileId = await
GridFsBucket.UploadFromStreamAsync(file.FileName, stream,
options);
return fileId.ToString();
}
}
public async Task<bool> AnyAsync(ObjectId id)
{
var filter = Builders<GridFSFileInfo>.Filter.Eq("_id", id);
return await GridFsBucket.Find(filter).AnyAsync();
}
public Task<bool> AnyAsync(string fileName)
{
var filter = Builders<GridFSFileInfo>.Filter.Where(x =>
x.Filename == fileName);
return GridFsBucket.Find(filter).AnyAsync();
}
public async Task DeleteAsync(string fileName)
{
var fileInfo = await GetFileInfoAsync(fileName);
if (fileInfo != null)
await DeleteAsync(fileInfo.Id);
}
public async Task DeleteAsync(ObjectId id)
{
await GridFsBucket.DeleteAsync(id);
}
private async Task<GridFSFileInfo> GetFileInfoAsync(string fileName)
{
var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename,
fileName);
var fileInfo = await
GridFsBucket.Find(filter).FirstOrDefaultAsync();
return fileInfo;
}
public async Task<GridFSDownloadStream<ObjectId>>
DownloadAsync(ObjectId id)
{
return await GridFsBucket.OpenDownloadStreamAsync(id);
}
public async Task<GridFSDownloadStream<ObjectId>>
DownloadAsync(string fileName)
{
return await
GridFsBucket.OpenDownloadStreamByNameAsync(fileName);
}
public IEnumerable<GridFSFileInfoDto> GetAllFilesByContentType(string
contentType, int skip, int take)
{
var filter = Builders<GridFSFileInfo>.Filter
.Eq(info => info.Metadata, new BsonDocument(new
BsonElement("contentType", contentType)));
var options = new GridFSFindOptions
{
Limit = take,
Skip = skip,
};
var stream = GridFsBucket.Find(filter, options)
.ToList()
.Select(s => new GridFSFileInfoDto
{
Id = s.Id,
Filename = s.Filename,
MetaData = s.Metadata,
Length = s.Length + "",
UploadDateTime = s.UploadDateTime,
})
.ToList();
return stream;
}
public IEnumerable<GridFSFileInfoDto> GetAllFiles(int skip, int take)
{
var options = new GridFSFindOptions
{
Limit = take,
Skip = skip,
};
var stream = GridFsBucket.Find(new
BsonDocumentFilterDefinition<GridFSFileInfo<ObjectId>>(new
BsonDocument()), options)
.ToList()
.Select(s => new GridFSFileInfoDto
{
Id = s.Id,
Filename = s.Filename,
MetaData = s.Metadata,
Length = s.Length + "",
UploadDateTime = s.UploadDateTime,
})
.ToList();
return stream;
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
then create a controller in .netcore web api
[EnableCors("AllowAll")]
[ValidateModel]
[Route("api/files")]
public class FileController : Controller
{
private readonly IGridFsRepository _gridFsManager;
public FileController(IGridFsRepository gridFsRepository)
{
_gridFsManager = gridFsRepository;
}
[AllowAnonymous]
[HttpGet("{fileName}",Name = "GetByFileName")]
public async Task<IActionResult> GetByFileName(string fileName)
{
return Ok(await _gridFsManager.DownloadAsync(fileName));
}
[AllowAnonymous]
[HttpGet("{id}",Name = "GetById")]
public async Task<IActionResult> GetByFileName(ObjectId id)
{
return Ok(await _gridFsManager.DownloadAsync(id));
}
[HttpPost]
public async Task<IActionResult> Upload([FromForm] IFormFile file)
{
if (file != null)
{
if (file.ContentType.Contains("image"))
return BadRequest("Sorry only image jpg/jpeg/png
accepted");
if (file.Length >= (300 * 1024))
return BadRequest($"Sorry {file.FileName} is exceeds
300kb");
await _gridFsManager.DeleteAsync(file.FileName);
await _gridFsManager.UploadAsync(file);
}
return NoContent();
}
[HttpDelete]
public async Task<IActionResult> Delete(string id)
{
await _gridFsManager.DeleteAsync(id);
return NoContent();
}
}
please do not forget to resolve dependency:
services.AddScoped<IGridFsRepository, GridFsRepository>();
to file from html:
<div class="btn">
<span>Logo</span>
<input type="file" data-ng-model="cp.data.file"
id="selectedFile" name="selectedFile">
</div>
lets go to UI layer:
first create an angular factory:
(function () {
"use strict";
angular.module("appCdn", [])
.factory('fileUploader', ["$http", function ($http) {
return {
upload: function (url, file, fileMaxSize, fileName, callback) {
if (this.isValidFileSize(fileMaxSize, file)) {
var fd = new FormData(); //Create FormData object
if (fileName)
fd.append("file", file, fileName);
else
fd.append("file", file);
$http.post(url, fd, {
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
}).success(function (data) {
callback();
}).error(function (data) {
Materialize.toast("Sorry! error in file upload", 4000, 'red');
});
} else {
Materialize.toast("Sorry! " + file.name + " exceeds 300kb", 4000, 'red');
}
},
isValidFileSize: function (maximumAllowedSize, file) {
if (file.size >= maximumAllowedSize) {
return false;
} else {
return true;
}
}
};
}
]);
})();
after that create an angular controller:
angular.module('ecom').controller('companyProfileCtrl',
['$http', 'config', "confirmation", "fileUploader",companyProfile]);
function companyProfile($http, config, confirmation, fileUploader) {
var vm = this; vm.getProfile = function () {
$http.get(config.apiUrl + "companyProfile")
.success(function (response) {
vm.data = response;
});
};
vm.save = function (profile) {
confirmation.confirm(function () {
$http.post(config.apiUrl + "companyProfile", profile)
.success(function (data) {
var fileName = "";
if (profile.id) {
fileName = profile.id;
} else {
fileName = data;
}
vm.upload(fileName,
function () {
Materialize.toast("succeeded", 4000, 'green');
window.location.href = window.history.back();
});
})
.error(function (data) {
Materialize.toast(data, 4000, 'red');
});
});
};
vm.upload = function (fileName, callback) {
var photo = document.getElementById("selectedFile");
var file = photo.files[0];
if (file) {fileUploader.upload(config.cdnUrl + "files",
//300kb
file, 1024 * 300, fileName, callback);
}
};
};
finally to show the image in html:
<div><img src="http://localhost:41792/api/files/{{cp.data.id}}"
class="img-responsive visible-md visible-lg img-margin-desktop"
width="350" height="167" />
</div>
finally we done this. this is all.
I always looking forward to receiving criticism.

Insert Image to database using typescript (angular2) and spring boot (spring data)

I start by presenting my client side the service
addImage (url: string, params: string[], files: File[]): Observable {
return Observable.create(observer => {
let formData: FormData = new FormData(),
xhr: XMLHttpRequest = new XMLHttpRequest();
for (let i = 0; i < files.length; i++) {
formData.append("uploads[]", files[i], file
s[i].name);
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
observer.next(JSON.parse(xhr.response));
observer.complete();
} else {
observer.error(xhr.response);
}
}
};
xhr.upload.onprogress = (event) => {
this.progress = Math.round(event.loaded / event.total * 100);
this.progressObserver.next(this.progress);
};
xhr.open('POST', url, true);
xhr.send(formData);
});
}
then this is my html code
<input type="file" (change)="uploadImage($event)"/>
where I call this method from my component
uploadImage(event) {
var files = event.srcElement.files;
console.log(files);
this._serviceSection.addImage('http://localhost:8080/template/img', [], files).subscribe(() => {
console.log('sent');
});
}
and in my service side
this is a method from my controller
#RequestMapping(value = "/img", method = RequestMethod.POST)
public void getFileContents(#RequestParam MultipartFile file) {
System.out.println("++++++++++++++++++++++++++++++++++++++++ " +file.getOriginalFilename());
}
in a first time a try just to show a fileName but I get this error
It seems that your progressObserver isn't set. The reason for this could be that you didn't subscribe to its associated observable. Don't forget that observables are lazy and if you don't subscribe to them, their initialization callback isn't called.
To prevent from having the error, you could check if it's null or not:
xhr.upload.onprogress = (event) => {
if (this.progressObserver) {
this.progress = Math.round(event.loaded / event.total * 100);
this.progressObserver.next(this.progress);
}
};
Otherwise, you can notice that from RC2, Angular2 accepts FormData objects as parameters of HTTP methods...

Dart web app not accessing MongoDB

I am trying to write a simple single-page web app in Dart using the "observatory" package. What it should do is display all the data in the "Name" collection, retrieve the user's input, add lastly that input to both the on-screen list and the collection. The input gets added to the unordered list, but that's all that happens. I'm not sure what I'm doing wrong. Here is my Dart code:
import 'dart:html';
import 'package:objectory/objectory_browser.dart';
class Name extends PersistentObject {
String get collectionName => "Name";
String get first => getProperty("first");
set first(String value) => setProperty("first", value);
String get last => getProperty("last");
set last(String value) => setProperty("last", value);
}
const uri = 'mongodb://localhost/dosdart1';
registerClasses() {
objectory.registerClass(Name, () => new Name(), () => new List<Name>());
}
void main() {
objectory = new ObjectoryWebsocketBrowserImpl(uri, registerClasses, false);
loadNames();
querySelector('#output').text = 'Your Dart app is running.';
var btn = querySelector('#btn');
btn.onClick.listen(addName);
}
Future display(name) {
var completer = new Completer();
name.fetchLinks().then((__) {
var ul = querySelector('#names');
var li = new LIElement()
..appendText("${name.first} ${name.last}");
ul.append(li);
completer.complete(true);
});
return completer.future;
}
loadNames() {
objectory.initDomainModel().then((_) {
return objectory[Name].find();
}).then((names){
return Future.wait(names.map((name) => display(name)));
}).then((_) {
objectory.close();
});
}
addName(MouseEvent e) {
var name = new Name();
InputElement firstElement = querySelector('#first');
InputElement lastElement = querySelector('#last');
name.first = firstElement.value;
name.last = lastElement.value;
objectory.initDomainModel().then((_){
name.save();
return;
}).then((_) {
objectory.close();
});
display(name);
}
And here is my web page:
<!DOCTYPE html>
<!--
Copyright (c) 2015, <your name>. All rights reserved. Use of this source code
is governed by a BSD-style license that can be found in the LICENSE file.
-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="scaffolded-by" content="https://github.com/google/stagehand">
<title>hybrid_dart</title>
<link rel="stylesheet" href="styles.css">
<script async src="main.dart" type="application/dart"></script>
<script async src="packages/browser/dart.js"></script>
</head>
<body>
<div id="output"></div>
<p><label for="first">First name:</label><input type="text" id="first" name="first"></p>
<p><label for="last">Last name:</label><input type="text" name="last" id="last"></p>
<p><button id="btn" name="btn" title="Insert">Insert</button></p>
<ul id="names">
</ul>
</body>
</html>
Does anybody have any ideas?
You need to chain futures to ensure they are executed in order. I don't see for every call if it returns a Future or a sync value therefore I might miss here and there (I added /* await */ where in doubt).
The new async / await feature makes it much easier to work with async code therefore I changed all your then(...) to async/await.
main() async {
objectory = new ObjectoryWebsocketBrowserImpl(uri, registerClasses, false);
await loadNames();
querySelector('#output').text = 'Your Dart app is running.';
var btn = querySelector('#btn');
btn.onClick.listen(addName);
}
Future display(name) async {
await fetchLinks();
var ul = querySelector('#names');
var li = new LIElement()
..appendText("${name.first} ${name.last}");
ul.append(li);
}
Future loadNames() async {
await objectory.initDomainModel();
var names = await objectory[Name].find();
await Future.wait(names.map((name) => display(name)));
/* await */ objectory.close();
}
Future addName(MouseEvent e) async {
var name = new Name();
InputElement firstElement = querySelector('#first');
InputElement lastElement = querySelector('#last');
name.first = firstElement.value;
name.last = lastElement.value;
await objectory.initDomainModel();
name.save();
/* await */ objectory.close();
await display(name);
}
Without async/await it should be like
void main() {
objectory = new ObjectoryWebsocketBrowserImpl(uri, registerClasses, false);
loadNames().then((_) {
querySelector('#output').text = 'Your Dart app is running.';
var btn = querySelector('#btn');
btn.onClick.listen(addName);
});
}
Future display(name) {
return name.fetchLinks().then((__) {
var ul = querySelector('#names');
var li = new LIElement()
..appendText("${name.first} ${name.last}");
ul.append(li);
});
}
Future loadNames() {
return objectory.initDomainModel().then((_) {
return objectory[Name].find();
}).then((names){
return Future.wait(names.map((name) => display(name)));
}).then((_) {
/* return */ objectory.close();
});
}
Future addName(MouseEvent e) {
var name = new Name();
InputElement firstElement = querySelector('#first');
InputElement lastElement = querySelector('#last');
name.first = firstElement.value;
name.last = lastElement.value;
return objectory.initDomainModel().then((_){
name.save();
return;
// if "name.save();" returns a Future this should be
// return name.save();
}).then((_) {
/* return */ objectory.close();
}).then((_) {
return display(name);
});
}
I finally solved the riddle using forcemvc and server-side MongoDB:
library serverweb2;
// add code to names() to retrieve all the names
// change names.html accordingly
import "package:forcemvc/force_mvc.dart";
import "package:objectory/objectory_console.dart";
import 'dart:async';
main(List<String> args) {
objectory = new ObjectoryDirectConnectionImpl('mongodb://127.0.0.1/serverweb2',
registerClasses, false);
var app = new WebApplication();
app.start();
// print('Hello world!');
}
#Controller
class Controllers {
#RequestMapping(value: "/", method: RequestMethod.GET)
String index(req, Model model) {
return "index";
}
#RequestMapping(value: "/names", method: RequestMethod.POST)
Future names(ForceRequest req, Model model) {
objectory.initDomainModel().then((_) {
req.getPostParams().then((params) {
var first = params['first'] as String;
var last = params['last'] as String;
var name = new Name()
..firstName = first
..lastName = last;
name.save();
return objectory[Name].find();
}).then((names) {
model.addAttribute('names', names);
return;
}).then((_){
req.async("names");
objectory.close();
});
});
return req.asyncFuture;
}
}
class Name extends PersistentObject {
String get collectionName => "Name";
String get firstName => getProperty("first_name");
set firstName(String value) {
setProperty("first_name", value);
}
String get lastName => getProperty('last_name');
set lastName(String value) {
setProperty('last_name', value);
}
#override
String toString() => "$firstName $lastName";
}
registerClasses() {
objectory.registerClass(Name, () => new Name(), () => new List<Name>());