Quickstart

This guide will get you up and running with Xams and covers the following:

  • Creating a Xams Api project
  • Creating a Xams React project
  • Creating tables
  • Displaying and creating records from a datatable
  • Writing service logic
  • Creating forms

Prerequisites

Install EF Core Tools

Ensure you have version 8+ of the Entity Framework Core tools installed.

Terminal

dotnet tool install --global dotnet-ef

Create Api Project

  1. In your c# IDE of choice create a new ASP.NET web based project using .NET 8
  2. Install the required nuget packages.

Terminal

dotnet add package Xams.Core
dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 8.0.14
dotnet add package Microsoft.EntityFrameworkCore.Design --version 8.0.14
  1. Create a new DbContext that inherits from XamsDbContext.

Project

public class DataContext : XamsDbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
var folder = Environment.SpecialFolder.LocalApplicationData;
var path = Environment.GetFolderPath(folder);
var dbPath = Path.Join(path, "app.db");
options.UseSqlite($"Data Source={dbPath}");
}
}
  1. Add the Xams services and provide the DbContext.

Program.cs

builder.Services.AddXamsServices<DataContext>();
  1. Add the Xams Api's and enable the dashboard.

Program.cs

// app.UseAuthentication();
// app.UseAuthorization();
app.AddXamsApi(options =>
{
options.UseDashboard = true;
});
  1. Create and run the migration.

Terminal

dotnet ef migrations add migration01
dotnet ef database update
  1. Run the project and navigate to the below path adding the port from the asp.net project.

http://localhost/xams/admin?userid=f8a43b04-4752-4fda-a89f-62bebcd8240c

  1. Enable CORS to allow the client application to connect

Program.cs

string corsPolicy = "_myAllowOrigins";
if (builder.Environment.IsDevelopment())
{
builder.Services.AddCors(x => x.AddPolicy(corsPolicy, builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyMethod()
.AllowAnyHeader();
}));
}

Program.cs

var app = builder.Build();
app.UseCors(corsPolicy);

Create React project

  1. Create a new react project using Vite or NextJS
  2. Install the Xams npm package and its dependencies.

Terminal

npm install dayjs@^1.11.13
npm install @mantine/core@^7.16.2 @mantine/dates@^7.16.2 @mantine/hooks@^7.16.2 @mantine/tiptap@^7.16.2 @tabler/icons-react@^2.40.0 @tiptap/extension-highlight@^2.1.12 @tiptap/extension-link@^2.11.3 @tiptap/extension-subscript@^2.1.12 @tiptap/extension-superscript@^2.1.12 @tiptap/extension-text-align@^2.1.12 @tiptap/extension-underline@^2.1.12 @tiptap/pm@^2.11.3 @tiptap/react@^2.11.3 @tiptap/starter-kit@^2.11.3 dayjs@^1.11.13 react-virtualized-auto-sizer@^1.0.22 react-window@^1.8.10 uuid@^9.0.0 zustand@^4.4.0 --legacy-peer-deps
npm install @ixeta/xams
  1. Configure the root component with the MantineProvider and Xams providers.

NextJs - _app.tsx

import "@/styles/globals.css";
import type { AppProps } from "next/app";
import "@mantine/core/styles.css";
import "@mantine/dates/styles.css";
import { MantineProvider } from "@mantine/core";
import {
AppContextProvider,
AuthContextProvider,
getQueryParam,
} from "@ixeta/xams";
import "@ixeta/xams/dist/styles.css";
import "@ixeta/xams/dist/global.css";
import { useRouter } from "next/router";
export default function App({ Component, pageProps }: AppProps) {
const router = useRouter();
const userId = getQueryParam("userid", router.asPath);
return (
<MantineProvider>
<AuthContextProvider
apiUrl={"https://localhost:8000"} // <- change to your api
headers={{
UserId: userId as string, // <- provide userid from query string in development
}}
>
<AppContextProvider>
<Component {...pageProps} />
</AppContextProvider>
</AuthContextProvider>
</MantineProvider>
);
}

Create an Entity

  1. In the "Common" project create a new class file in the Entities folder and name it "Widget.cs"

Project.Common / Entities / Widget.cs

[Table("Widget")]
public class Widget
{
public Guid WidgetId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
  1. Add the Widget class to the DataContext class.

Project.Data / DataContext.cs

public class DataContext : XamsDbContext
{
public DbSet<Widget> Widgets { get; set; }
...
}
  1. In the Project.Data directory execute the code below to create a migration and update the database.

Terminal

dotnet ef migrations add migration02
dotnet ef database update
  1. Start the project

Create a Datatable

  1. Paste the following code in index.tsx

src / pages / index.tsx

import { DataTable } from '@ixeta/xams'
import React from 'react'
const Index = () => {
return (
<div className="h-96 w-[500px] p-10">
<DataTable tableName="Widget"></DataTable>
</div>
)
}
export default Index

This will create the following table.

If you click the "Add" button on the table, a form will open where a new record can be created.

Add Service Logic

We can have the service layer automatically set a price for the Widget based on the number of Widgets in the database.

  1. Create a new class file in the Project.Services/ServiceLogic folder. Name it "WidgetService.cs"
  2. Replace the class in the file with the code below.

Project.Services / ServiceLogic / WidgetService.cs

// Execute on Create or Update of the Widget entity before the Save to the database.
[ServiceLogic(nameof(Widget), DataOperation.Create | DataOperation.Update, LogicStage.PreOperation)]
public class WidgetService : IServiceLogic
{
public async Task<Response<object?>> Execute(ServiceContext context)
{
var db = context.GetDbContext<DataContext>();
// Get the entity being saved
Widget widget = context.GetEntity<Widget>();
var countWidgets = await db.Widgets.CountAsync();
// Only set on create
if (context.DataOperation is DataOperation.Create)
{
// Because this is a PreOperation (before save), the Price will
// eventually get saved to the database
widget.Price = countWidgets * 10.5M;
}
return ServiceResult.Success();
}
}

Create a Record

  1. Replace the code in index.tsx with the following.

src / pages / index.tsx

import { useAuthRequest } from '@ixeta/xams'
import { Button } from '@mantine/core'
import React from 'react'
const Index = () => {
const authRequest = useAuthRequest()
const onClick = async () => {
const resp = await authRequest.create('Widget', {
Name: 'My Widget',
Price: 9.99,
})
if (!resp.succeeded) {
return
}
}
return <Button onClick={onClick}>Create Widget</Button>
}
export default Index

When the button is clicked, a Widget record will be created with the provided data.

Create a Form

  1. Replace the code in index.tsx with the following.

src / pages / index.tsx

import { Field, FormContainer, SaveButton, useFormBuilder } from '@ixeta/xams'
import { Grid } from '@mantine/core'
import React from 'react'
const Index = () => {
// Use the useFormBuilder hook to specify the table we're creating the form for
const formBuilder = useFormBuilder({
tableName: 'Widget',
})
return (
<div className="h-full w-full max-w-md p-6">
{/* Create a form container for this table's fields */}
<FormContainer formBuilder={formBuilder}>
<div className="flex flex-col gap-4">
<Grid>
<Grid.Col span={6}>
{/* Define the table fields to bind to */}
<Field name="Name" />
</Grid.Col>
<Grid.Col span={6}>
<Field name="Price" />
</Grid.Col>
</Grid>
<SaveButton />
</div>
</FormContainer>
</div>
)
}
export default Index

This will create the below form:

Was this page helpful?