I have the following in my Global.asax.cs:
using System.Web.Mvc;
using System.Web.Routing;
using HandiGamer.WebUI.ConditionalValidation;
using HandiGamer.Domain.Concrete;
using Ninject;
using Ninject.Web.Common;
using System.Reflection;
using HandiGamer.Domain.Abstract;
//namespace....
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("favicon.ico");
routes.MapRoute(
null,
"Reviews/{id}",
new { controller = "Reviews", action = "ShowReviewById" },
new { id = #"\d+" }
);
routes.MapRoute(
null,
"Reviews/Latest",
new { controller = "Reviews", action = "Latest"}
);
routes.MapRoute(
null,
"Reviews/{slug}",
new { controller = "Reviews", action = "ShowReviewBySlug" },
new { slug = #"[0-9a-zA-Z\-]+" }
);
routes.MapRoute(
null,
"News/{id}",
new { controller = "News", action = "ShowNewsById" },
new { id = #"\d+" }
);
routes.MapRoute(
null,
"News/{slug}",
new { controller = "News", action = "ShowNewsBySlug" },
new { slug = #"[0-9a-zA-Z\-]" }
);
routes.MapRoute(
null,
"Articles/{id}",
new { controller = "Articles", action = "ShowArticleById" },
new { id = #"\d+" }
);
routes.MapRoute(
null,
"Articles/{slug}",
new { controller = "Articles", action = "ShowArticleBySlug" },
new { slug = #"[0-9a-zA-Z\-]" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
null,
"{*path}",
new { controller = "Error", action = "Http404" }
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute), typeof(RequiredIfValidator));
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IArticleRepository>().To<HGArticleRepository>();
kernel.Bind<IGameRepository>().To<HGGameRepository>();
kernel.Bind<INewsRepository>().To<HGNewsRepository>();
kernel.Load(Assembly.GetExecutingAssembly());
return kernel;
}
}
But upon building my solution, I get the following error:
Error 1 'HandiGamer.MvcApplication.CreateKernel()': no suitable method found to override C:\Users\Kevin\documents\visual studio 2010\Projects\HandiGamer\HandiGamer\Global.asax.cs 92 36 HandiGamer.WebUI
Any ideas? I've pretty much copied what was in the github sample app, so I'm stumped.
You have to derive from NinjectHttpAplication
Related
I am new to Identity server, recently set it up for a project, but I keep getting the following error
Sorry, there was an error : invalid_scope Invalid scope
These are the components that comprise the application.
Web Client -> ASPNETCORE Razor Pages application (Port: 7091)
Ocelot -> API Gateway
Identity Server 6 (Port: 5001)
StripeDotNet -> API
Basket -> API
My configurations/code are as follows:
Identity Server
public static class Config
{
public static IEnumerable<IdentityResource> IdentityResources =>
new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
// new IdentityResources.Email(),
};
public static IEnumerable<ApiScope> ApiScopes =>
new List<ApiScope>
{
new ApiScope("stripedotnetapi", "StripeDotNet API")
};
public static IEnumerable<Client> Clients =>
new List<Client>
{
// interactive ASP.NET Core MVC client
new Client
{
ClientId = "razorweb",
ClientName = "Razor Web",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
// where to redirect to after login
RedirectUris = { "https://localhost:7091/signin-oidc" },
//FrontChannelLogoutUri = "https://localhost:7091/signout-callback-oidc",
// where to redirect to after logout
PostLogoutRedirectUris = { "https://localhost:7091/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
// IdentityServerConstants.StandardScopes.Email,
"stripedotnetapi"
}
}
};
}
Identity Server: Hosting Extensions
builder.Services
.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
// see https://docs.duendesoftware.com/identityserver/v6/fundamentals/resources/
options.EmitStaticAudienceClaim = true;
})
.AddInMemoryIdentityResources(Config.IdentityResources)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients)
.AddAspNetIdentity<ApplicationUser>();
StripeDotNet API
public static IServiceCollection AddSecurityServices(this IServiceCollection services)
{
services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
options.Authority = "https://localhost:5001";
options.TokenValidationParameters.ValidateAudience = false;
});
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "stripedotnetapi");
});
});
return services;
}
StripeDotNet API: Controller Code
[Route("api/[controller]")]
[Authorize("ApiScope")]
public class CheckoutController : BaseController
{
private readonly ICheckoutService _checkoutService;
public CheckoutController(ICheckoutService checkoutService)
{
_checkoutService = Guard.Against.Null(checkoutService, nameof(checkoutService));
}
[HttpGet]
public async Task<IActionResult> CreateCheckoutSession([FromBody] CreateCheckoutSessionRequest req)
{
var response = await _checkoutService.CreateCheckoutSessionAsync(req.TenantId, req.PriceId,
req.SuccessUrl, req.CancelUrl);
return Ok(response);
}
[HttpGet("{sessionId}")]
public async Task<IActionResult> GetCheckoutSession(string sessionId)
{
var response = await _checkoutService.GetCheckoutSessionAsync(sessionId);
return Ok(response);
}
}
Ocelot API Gateway
var authenticationProviderKey = "IdentityApiKey";
builder.Services.AddAuthentication()
.AddJwtBearer(authenticationProviderKey, x =>
{
x.Authority = "https://localhost:5001"; // IDENTITY SERVER URL
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
Ocelot API Gateway: Configuration file
{
"UpStreamPathTemplate": "/api/Checkout",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7056
}
],
"DownstreamPathTemplate": "/api/Checkout",
"AuthenticationOptions": {
"AuthenticationProviderKey": "IdentityApiKey",
"AllowedScopes": []
}
},
{
"UpStreamPathTemplate": "/api/Checkout/{sessionId}",
"UpstreamHttpMethod": [ "Get" ],
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7056
}
],
"DownstreamPathTemplate": "/api/Checkout/{sessionId}",
"AuthenticationOptions": {
"AuthenticationProviderKey": "IdentityApiKey",
"AllowedScopes": []
}
},
Web Client
public static IServiceCollection AddSecurityServices(this IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.ClientId = "razorweb";
options.ClientSecret = "secret";
options.ResponseType = "code";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
//options.Scope.Add("email");
options.Scope.Add("stripedotnetapi");
options.Scope.Add("offline_access");
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
});
return services;
}
My discovery endpoint shows these items as valid scopes
"scopes_supported": [
"openid",
"profile",
"stripedotnetapi",
"offline_access"
],
The supported scopes appear to be setup correctly for the web client, but I keep getting an invalid scope error. Any guidance would be greatly appreciated.
Solved. I didnt pay close enough attention to the docs. Offline Access was not granted to the client.
AllowOfflineAccess = true,
Learning swiftui by building an app with core data; stuck in an issue of data flow from Detail to Edit of AddEdit; the flows from AddEdit to List and from List to Detail are ok. Searched but didn't find useful info online or I don't understand. Here is a simplified project for the question. It complies ok on 13.2 beta and works on simulator, with the issue of blank Edit view from Detail.
views:
struct FileList: View {
#FetchRequest(sortDescriptors: [ NSSortDescriptor(keyPath: \Item.fileName, ascending: false) ], animation: .default) var items: FetchedResults<Item>
#State private var showAdd = false
var body: some View {
NavigationView {
List {
ForEach(items) { item in
NavigationLink(destination: FileDetail(item: item)) {
Text(item.fileName ?? "").font(.headline)
}
}
}
.navigationTitle("List")
.navigationBarItems(trailing: Button(action: {
showAdd = true
}, label: { Image(systemName: "plus.circle")
})
.sheet(isPresented: $showAdd) {
FileAddEdit(items: VM())
}
)
}
}
}
struct FileList_Previews: PreviewProvider {
static let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
static var previews: some View {
FileList()
}
}
struct FileDetail: View {
#Environment(\.managedObjectContext) var context
#Environment(\.presentationMode) var presentationMode
#State var showingEdit = false
#ObservedObject var item: Item
var body: some View {
VStack {
Form {
Text(self.item.fileName ?? "File Name")
Button(action: {
showingEdit.toggle()
}, label: {
title: do { Text("Edit")
}
})
.sheet(isPresented: $showingEdit) {
FileAddEdit(items: VM())
}
}
}.navigationTitle("Detail")
}
}
struct FileDetails_Previews: PreviewProvider {
static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
static var previews: some View {
let item = Item(context: moc)
return NavigationView {
FileDetail(item: item)
}
}
}
struct FileAddEdit: View {
#Environment(\.managedObjectContext) var moc
#ObservedObject var items = VM()
var body: some View {
NavigationView {
VStack {
Form {
TextField("File Name", text: $items.fileName)
Button(action: {
items.writeData(context: moc)
}, label: {
title: do { Text(items.updateFile == nil ? "Add" : "Edit")
}})
}
}
.navigationTitle("\(items.updateFile == nil ? "Add" : "Edit")")
}
}
}
struct FileAddEdit_Previews: PreviewProvider {
static var previews: some View {
FileAddEdit(items: VM())
}
}
VM:
class VM: ObservableObject {
#Published var fileName = ""
#Published var id = UUID()
#Published var isNewData = false
#Published var updateFile : Item!
init() {
}
var temporaryStorage: [String] = []
func writeData(context : NSManagedObjectContext) {
if updateFile != nil {
updateCurrentFile()
} else {
createNewFile(context: context)
}
do {
try context.save()
} catch {
print(error.localizedDescription)
}
}
func DetailItem(fileItem: Item){
fileName = fileItem.fileName ?? ""
id = fileItem.id ?? UUID()
updateFile = fileItem
}
func EditItem(fileItem: Item){
fileName = fileItem.fileName ?? ""
id = fileItem.id ?? UUID()
isNewData.toggle()
updateFile = fileItem
}
private func createNewFile(context : NSManagedObjectContext) {
let newFile = Item(context: context)
newFile.fileName = fileName
newFile.id = id
}
private func updateCurrentFile() {
updateFile.fileName = fileName
updateFile.id = id
}
private func resetData() {
fileName = ""
id = UUID()
isNewData.toggle()
updateFile = nil
}
}
Much appreciated for your time and advices!
Here is a simplified version of your code Just paste this code into your project and call YourAppParent() in a body somewhere in your app as high up as possible since it creates the container.
import SwiftUI
import CoreData
//Class to hold all the Persistence methods
class CoreDataPersistence: ObservableObject{
//Use preview context in canvas/preview
let context = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" ? PersistenceController.preview.container.viewContext : PersistenceController.shared.container.viewContext
///Creates an NSManagedObject of **ANY** type
func create<T: NSManagedObject>() -> T{
T(context: context)
//For adding Defaults see the `extension` all the way at the bottom of this post
}
///Updates an NSManagedObject of any type
func update<T: NSManagedObject>(_ obj: T){
//Make any changes like a last modified variable
//Figure out the type if you want type specific changes
if obj is FileEnt{
//Make type specific changes
let name = (obj as! FileEnt).fileName
print("I'm updating FileEnt \(name ?? "no name")")
}else{
print("I'm Something else")
}
save()
}
///Creates a sample FileEnt
//Look at the preview code for the `FileEdit` `View` to see when to use.
func addSample() -> FileEnt{
let sample: FileEnt = create()
sample.fileName = "Sample"
sample.fileDate = Date.distantFuture
return sample
}
///Deletes an NSManagedObject of any type
func delete(_ obj: NSManagedObject){
context.delete(obj)
save()
}
func resetStore(){
context.rollback()
save()
}
func save(){
do{
try context.save()
}catch{
print(error)
}
}
}
//Entry Point
struct YourAppParent: View{
#StateObject var coreDataPersistence: CoreDataPersistence = .init()
var body: some View{
FileListView()
//#FetchRequest needs it
.environment(\.managedObjectContext, coreDataPersistence.context)
.environmentObject(coreDataPersistence)
}
}
struct FileListView: View {
#EnvironmentObject var persistence: CoreDataPersistence
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \FileEnt.fileDate, ascending: true)],
animation: .default)
private var allFiles: FetchedResults<FileEnt>
var body: some View {
NavigationView{
List{
//Has to be lazy or it will create a bunch of objects because the view gets preloaded
LazyVStack{
NavigationLink(destination: FileAdd(), label: {
Text("Add file")
Spacer()
Image(systemName: "plus")
})
}
ForEach(allFiles) { aFile in
NavigationLink(destination: FileDetailView(aFile: aFile)) {
Text(aFile.fileDate?.description ?? "no date")
}.swipeActions(edge: .trailing, allowsFullSwipe: true, content: {
Button("delete", role: .destructive, action: {
persistence.delete(aFile)
})
})
}
}
}
}
}
struct FileListView_Previews: PreviewProvider {
static var previews: some View {
YourAppParent()
// let pers = CoreDataPersistence()
// FileListView()
// #FetchRequest needs it
// .environment(\.managedObjectContext, pers.context)
// .environmentObject(pers)
}
}
struct FileDetailView: View {
#EnvironmentObject var persistence: CoreDataPersistence
#ObservedObject var aFile: FileEnt
#State var showingFileEdit: Bool = false
var body: some View{
Form {
Text(aFile.fileName ?? "")
}
Button(action: {
showingFileEdit.toggle()
}, label: {
Text("Edit")
})
.sheet(isPresented: $showingFileEdit, onDismiss: {
//Discard any changes that were not saved
persistence.resetStore()
}) {
FileEdit(aFile: aFile)
//sheet needs reinject
.environmentObject(persistence)
}
}
}
///A Bridge to FileEdit that creates the object to be edited
struct FileAdd:View{
#EnvironmentObject var persistence: CoreDataPersistence
//This will not show changes to the variables in this View
#State var newFile: FileEnt? = nil
var body: some View{
Group{
if let aFile = newFile{
FileEdit(aFile: aFile)
}else{
//Likely wont ever be visible but there has to be a fallback
ProgressView()
.onAppear(perform: {
newFile = persistence.create()
})
}
}
.navigationBarHidden(true)
}
}
struct FileEdit: View {
#EnvironmentObject var persistence: CoreDataPersistence
#Environment(\.dismiss) var dismiss
//This will observe changes to variables
#ObservedObject var aFile: FileEnt
var viewHasIssues: Bool{
aFile.fileDate == nil || aFile.fileName == nil
}
var body: some View{
Form {
TextField("required", text: $aFile.fileName.bound)
//DatePicker can give the impression that a date != nil
if aFile.fileDate != nil{
DatePicker("filing date", selection: $aFile.fileDate.bound)
}else{
//Likely wont ever be visible but there has to be a fallback
ProgressView()
.onAppear(perform: {
//Set Default
aFile.fileDate = Date()
})
}
}
Button("save", role: .none, action: {
persistence.update(aFile)
dismiss()
}).disabled(viewHasIssues)
Button("cancel", role: .destructive, action: {
persistence.resetStore()
dismiss()
})
}
}
extension Optional where Wrapped == String {
var _bound: String? {
get {
return self
}
set {
self = newValue
}
}
var bound: String {
get {
return _bound ?? ""
}
set {
_bound = newValue
}
}
}
extension Optional where Wrapped == Date {
var _bound: Date? {
get {
return self
}
set {
self = newValue
}
}
public var bound: Date {
get {
return _bound ?? Date.distantPast
}
set {
_bound = newValue
}
}
}
For adding a preview that requires an object you can use this code with the new CoreDataPersistence
///How to create a preview that requires a CoreData object.
struct FileEdit_Previews: PreviewProvider {
static let pers = CoreDataPersistence()
static var previews: some View {
VStack{
FileEdit(aFile: pers.addSample()).environmentObject(pers)
}
}
}
And since the create() is now generic you can use the Entity's extension to add defaults to the variables.
extension FileEnt{
public override func awakeFromInsert() {
//Set defaults here
self.fileName = ""
self.fileDate = Date()
}
}
Below is a working example I made that extends the default Core Data SwiftUI app template to add editing of the Item's timestamp in a sheet. The sheet loads the item in the child context so edits can be made and if cancelled the edits are discarded but if saved then the changes are pushed in to the view context and it is saved. If you are unfamilar with child contexts for editing I recommend Apple's old CoreDataBooks sample project.
The main thing you need to know is when we are using a sheet to edit something we use the version that takes an item rather than a boolean. That allows you to configure the editing View correctly.
import SwiftUI
import CoreData
struct ItemEditorConfig: Identifiable {
let id = UUID()
let context: NSManagedObjectContext
let item: Item
init(viewContext: NSManagedObjectContext, objectID: NSManagedObjectID) {
// create the scratch pad context
context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context.parent = viewContext
// load the item into the scratch pad
item = context.object(with: objectID) as! Item
}
}
struct ItemEditor: View {
#ObservedObject var item: Item // this is the scratch pad item
#Environment(\.managedObjectContext) private var context
#Environment(\.dismiss) private var dismiss
let onSave: () -> Void
#State var errorMessage: String?
var body: some View {
NavigationView {
Form {
Text(item.timestamp!, formatter: itemFormatter)
if let errorMessage = errorMessage {
Text(errorMessage)
}
Button("Update Time") {
item.timestamp = Date()
}
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel") {
dismiss()
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button("Save") {
// first save the scratch pad context then call the handler which will save the view context.
do {
try context.save()
errorMessage = nil
onSave()
} catch {
let nsError = error as NSError
errorMessage = "Unresolved error \(nsError), \(nsError.userInfo)"
}
}
}
}
}
}
}
struct DetailView: View {
#Environment(\.managedObjectContext) private var viewContext
#ObservedObject var item: Item
#State var itemEditorConfig: ItemEditorConfig?
var body: some View {
Text("Item at \(item.timestamp!, formatter: itemFormatter)")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: edit) {
Text("Edit")
}
}
}
.sheet(item: $itemEditorConfig, onDismiss: didDismiss) { config in
ItemEditor(item: config.item) {
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
itemEditorConfig = nil
}
.environment(\.managedObjectContext, si.context)
}
}
func edit() {
itemEditorConfig = ItemEditorConfig(viewContext: viewContext, objectID: item.objectID)
}
func didDismiss() {
// Handle the dismissing action.
}
}
struct ContentView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
var body: some View {
NavigationView {
List {
ForEach(items) { item in
NavigationLink {
DetailView(item: item)
} label: {
Text(item.timestamp!, formatter: itemFormatter)
}
}
.onDelete(perform: deleteItems)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
Text("Select an item")
}
}
private func addItem() {
withAnimation {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
private let itemFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter
}()
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
I want to display some data I am receiving from an API, this is the data I am receiving from my Node JS server:
[
{
"NAME": "Matematicas"
},
{
"NAME": "Naturales"
},
{
"NAME": "Ciencias Sociales"
},
{
"NAME": "Lenguaje"
},
{
"NAME": "Religion"
}
]
This is how I am receiving the data in my front end (UPDATED WITH #Mofidul Islam):
Future<List<Subject>> fetchSubject() async {
var url = Uri.http('localhost:8000', "/subjects");
var prefs = await SharedPreferences.getInstance();
var token = prefs.getString('token');
final response = await http.get(
Uri.parse('http://localhost:8000/subjects'),
headers: {'x-access-token': token!});
print(response.body);
List<dynamic> list = "[" + response.body + "]" as List<dynamic>;
List<Subject> subjectList = [];
list.forEach((element) {
subjectList.add(Subject.fromJson(element));
});
return subjectList;
}
This is the class to handle the incoming data (UPDATED WITH #Mofidul Islam):
class Subject {
final String name;
Subject({
required this.name,
});
factory Subject.fromJson(Map<String, dynamic> json) {
return Subject(name: json['NAME'] as String);
}
parseJson(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Subject>((json) => Subject.fromJson(json)).toList();
}
}
This is my init state:
void initState() {
super.initState();
futureSubject = fetchSubject();
}
This is how I am trying to display the data:
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Materias',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Materias'),
),
body: Center(
child: FutureBuilder<List<Subject>>(
future: futureSubject,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data!
.map((subject) => Text(subject.name))
.toList(),
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
),
),
);
}
However, the only thing being displayed when the page loads is:
Matematicas
I am trying to achieve 2 things:
Display the data in a list fashion like:
Subject Name
Matematicas
Naturales
Ciencias Sociales
Lenguaje Religion
Be able to use them as a link to another page when clicked
PD: If I remove the index access [0] on return Subject.fromJson(jsonDecode(response.body)[0]);
I get Expected a value of type Map<String, dynamic> but got one of type List<dynamic>
Any recommendations or guide on how to go through this?
Thank you for your time
You need to loop it
parseJson(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed
.map<Subject>((json) => Subject.fromJson(json))
.toList();
}
and change your api call to this
Future<List<Subject>> fetchSubject() async {
.....
return parseJson(json.encode(response.body));
}
sorry for my english.
Please try this one and return List from api method
Future<List<Subject>> fetchSubject() async {
var url = Uri.http('localhost:8000', "/subjects");
var prefs = await SharedPreferences.getInstance();
var token = prefs.getString('token');
final response = await http.get(Uri.parse('http://localhost:8000/subjects'),
headers: {'x-access-token': token!});
List<dynamic>list=response.body as List<dynamic>;
List<Subject>subjectList=[];
list.forEach((element){
subjectList.add(Subject.fromJson(element));
});
return subjectList;
}
refactor UI like this
Center(
child: FutureBuilder<List<Subject>>(
future: futureSubject,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(children: snapshot.data.map((subject)=>Text(subject.name)).toList(),);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
)
On the button click event of React side I am calling a node backend.
click event of react,
// calling node backend
this.uploadApi.command(postData.bin_files, this.dummy);
this.setState({submit_form});
}
dummy = (result)=>{
console.log(result);
}
This is my Node backend code,
import axios from 'axios';
class UploadFile {
constructor() {
this.url = 'http://localhost:56246/microservice/uploaddata'; //This is the local MVC application's URL (microservice is the controller)
}
command(postData, callback, uploadCallback = null) {
let jsonDataString = JSON.stringify(postData).replace(/&/g, '--and--');
jsonDataString = jsonDataString.replace(/\+/g, '--plus--');
const payload = JSON.parse(jsonDataString);
console.log('----------');
console.log(this.url);
console.log(payload);
console.log('----------');
// var data = qs.stringify({'jsondata':payload});
const data = new FormData();
for (var i = 0; i < payload.length; i++) {
console.log('inside for 1');
data.append(`model[${i}].name`, payload[i].name);
data.append(`model[${i}].bin_file`, payload[i].bin_file);
console.log('inside for 2');
}
console.log('=============');
console.log(data);
console.log('=============');
var config = {
method: 'post',
url: this.url,
headers: {
'Content-Type': 'multipart/form-data'
},
data: "jsondata=" + data,
onUploadProgress: (progressEvent) => {
const {
loaded,
total
} = progressEvent;
console.log("loaded:", loaded);
console.log("total:", total);
if (uploadCallback !== null) uploadCallback(progressEvent);
}
};
axios(config)
.then(function(response) {
// console.log(JSON.stringify(response.data));
callback(response.data);
})
.catch(function(error) {
console.log(error);
});
// axios.post(this.url, data)
// .then(res => console.log(res.data))
// .catch((error) => { console.error(error) });
}
}
export default UploadFile;
And this is my respective controller,
public dynamic UploadData(List<MemberInfo> model)
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = mstrDBConStringNew;
conn.Open();
SqlCommand command = new SqlCommand("SELECT * from tempstorage", conn);
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
//port = reader.GetString(0);
}
}
}
return "Hiiiiiiii";
}
public class MemberInfo
{
public string name { get; set; }
public string bin_file { get; set; }
}
Now If I show You while debugging, the controller and its respective action gets called but the value that I am expecting is null.
I have also tried like this way, but no luck
public dynamic UploadData(FormCollection model)
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = mstrDBConStringNew;
conn.Open();
SqlCommand command = new SqlCommand("SELECT * from tempstorage", conn);
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
//port = reader.GetString(0);
}
}
}
return "Hiiiiiiii";
}
This is my network request,
Please ask if anything additional is needed.
Yes I was able to figure out the issue,
var config = {
method: 'post',
url: this.url,
headers: {
'Content-Type': 'multipart/form-data'
},
data: data, // previously it was, "jsondata=" + data
Here I am getting the data as expected..
I have following object ICoreFileStat, which on the server side, URI will be a class created using vscode-uri. How do I convert only URI to string recursively?
export interface ICoreFileStat extends ICoreBaseStat {
children?: ICoreFileStat[];
}
export interface ICoreBaseStat {
resource: URI | string;
name?: string;
}
What I was expecting the URI in the above object will be transformed to string like (file:///index.js) and it will be a plain object like below.
const data = {
children: {
resource: "///file://tmp"
children: {
resource: "///file:/index.js"
}
}
Here is the solution, I came up with. But I would like to see others solutions as well.
const serialize = (stat: IFileStat) => Object.keys(stat).reduce((result, name) => {
// console.log(result);
if (name === 'resource') {
return result = { ...stat, resource: stat[name].toString() };
} else if (name === 'children') {
return { ...result, ...{ children: stat[name].map(child => serialize(child as any)) } }
}
else {
return result
}
}, {});