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)
{
base.OnConfiguring(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. Remove the property naming policy.

Program.cs

builder.Services.AddXamsServices<DataContext>();
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
  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. You can access the admin dashboard by navigating to /x in your browser. In development you can provide the user id of any user you want to impersonate via the query string. For example, to impersonate the SYSTEM user:

http://localhost/x?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 using React v18.
  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 ASP.NET project create a new class file in the Entities folder and name it "Widget.cs"

Project / 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 / DataContext.cs

public class DataContext : XamsDbContext
{
public DbSet<Widget> Widgets { get; set; }
...
}
  1. In the ASP.NET project 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 folder named Logic. Create a new class file in the Logic folder and name it "WidgetService.cs"
  2. Replace the class in the file with the code below.

Project / Logic / 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?