Muslim.GenericService
10.0.1
dotnet add package Muslim.GenericService --version 10.0.1
NuGet\Install-Package Muslim.GenericService -Version 10.0.1
<PackageReference Include="Muslim.GenericService" Version="10.0.1" />
<PackageVersion Include="Muslim.GenericService" Version="10.0.1" />
<PackageReference Include="Muslim.GenericService" />
paket add Muslim.GenericService --version 10.0.1
#r "nuget: Muslim.GenericService, 10.0.1"
#:package Muslim.GenericService@10.0.1
#addin nuget:?package=Muslim.GenericService&version=10.0.1
#tool nuget:?package=Muslim.GenericService&version=10.0.1
Muslim.GenericService
A generic service layer for .NET 10 on top of
Muslim.GenericRepository. One class,
Service<TEntity>, gives every table reads, DTO projection, paging with Muslim.Filter, create and
update with validation, soft delete and restore, bulk deletes and counts, and returns a
Muslim.Result Result<T> instead of throwing.
dotnet add package Muslim.GenericService
dotnet add package Muslim.GenericRepository
This package depends on the repository interface only; add Muslim.GenericRepository (or your
own IRepository<T> implementation) to the application.
The service contract, IService<TEntity> and the interfaces it combines, is in
Muslim.GenericService.Interface,
which comes with this package. Projects that only call services (controllers, other libraries)
can reference that package alone. The namespaces are Muslim.GenericService and
Muslim.GenericService.Interfaces.
Full documentation: genericservice.netlify.app
Quick start
Set up the repository as its README describes (DbContext, AutoMapper, ICurrentUser,
BaseRepository.SetDbContext<T>(), and InjectExtensions.SetServiceProvider at startup and per
request). Then register validators and the generic types:
using FluentValidation;
using Muslim.GenericRepository.Interface;
using Muslim.GenericRepository.Repositories;
using Muslim.GenericService;
builder.Services.AddValidatorsFromAssemblyContaining<NoteDtoValidator>();
builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
builder.Services.AddScoped(typeof(IService<>), typeof(Service<>));
Inject IService<Note> and use it:
public class NotesController(IService<Note> notes) : ControllerBase
{
[HttpPost]
public async Task<IActionResult> Create(NoteDto request)
{
var result = await notes.CreateAsync(request); // validated, inserted, Id filled
return result.IsSuccess ? Ok(result) : BadRequest(result);
}
}
For a service with its own methods, derive from Service<T> and pass the repository to the base
constructor. AddAutoInjection registers it:
public interface INoteService : IService<Note>
{
Task<int> CountArchivedAsync();
}
public class NoteService(INoteRepository repository) : Service<Note>(repository), INoteService
{
public Task<int> CountArchivedAsync() => CountAsync(x => x.IsDeleted);
}
What you get back
| Member | Meaning |
|---|---|
IsSuccess |
The call worked. A missing row from GetById/FirstOrDefault/SingleOrDefault is still a success with Response == null. |
Response |
The value. |
Error |
Exception messages, or one message per failed item in range operations. |
ValidatorError |
Property name and message for each validation failure. |
Page |
Count (all matching rows), PageSize, NumberOfPages for Find*. |
Any, Count, ExecuteSql* and FromSqlInterpolated return plain values: -1 (or false,
null) on error.
Validation
Create* and Update* validate DTOs with FluentValidation through Muslim.Validator before writing.
Register a validator for every DTO you pass, even an empty one; a DTO with no validator fails
validation. Validators are resolved from the current Muslim.Inject scope (the per-request provider),
so scoped validators work. Without one, the provider given to ValidateResult.SetServiceProvider is
used. CreateAsync(TEntity) does not validate.
Paging
Find(filter) and Find<TDto>(filter) with a Muslim.Filter IFilter<TEntity> return one page, and
Page.Count is the number of all matching rows. The overloads that take a condition and a
pageSize return every match; pageSize only fills Page.NumberOfPages.
Good to know
- Every write commits on its own. For several writes in one transaction, use the repositories'
staging methods and one
Save(). FirstOrDefaultAsync<TDto>(x => ...),SingleOrDefault<TDto>(x => ...)andSingleOrDefaultAsync<TDto>(x => ...)are ambiguous (CS0121) when the entity and the DTO share the property. Type the parameter:(Note x) => x.Title == title.DeleteRangeByIdsAsyncandSoftDeleteRange*handle each item separately: successes inResponse, failures inError.- All public methods are
virtual. Async methods do not take aCancellationToken. Service<TEntity>is apartialclass split by concern (Services/Read,Services/Write,Services/SqlOperations), likeRepository<TEntity>.
The full behavior of every method, with examples and troubleshooting, is in the agent guide that
ships in this package (skills/muslim-genericservice/), readable as plain Markdown.
Coding-agent guidance
The package contains a short guide for AI coding agents: an Agent Skills
SKILL.md and two reference files under skills/muslim-genericservice/ in the .nupkg. It
describes this version's API, setup and pitfalls, so an agent can use the package without reading
its source. A buildTransitive/Muslim.GenericService.targets file copies it into your repository.
Where and when it appears
- When a project that references Muslim.GenericService (directly, or through another package or
project) builds, the guide is copied to
.agents/skills/muslim-genericservice/at the repository root. Installing or restoring alone does nothing; the files appear after the first build, from the command line or an IDE. - The repository root is the nearest folder above the project that contains
.git(a folder, or a file for worktrees and submodules). Without one, the nearest folder with a.slnor.slnxfile is used, and failing that the project's own folder. The current working directory does not matter. - Design-time builds (IDE background analysis) do not write files.
- Next to the guide the build writes
package-version.txt(the version it belongs to),.muslim-genericservice.manifest(which files the package owns, with their hashes) and.muslim-genericservice.lock. Commit the folder or add it to.gitignore, as you prefer.
Which agents read it
.agents/skills/ is a shared, project-level skills location. Agents documented or reported to read
it include OpenAI Codex, GitHub Copilot in VS Code, Gemini CLI, Cursor and OpenCode. Support depends
on the agent and its version; check your agent's documentation. The package was not tested against
each agent.
Claude Code does not read .agents/skills/; it reads .claude/skills/. To use the guide there,
copy or link the folder to .claude/skills/muslim-genericservice/, or mention it in CLAUDE.md.
Most agents look for skills when a session starts. Start a new agent session after the first build (and after an upgrade); a session that is already running may not see the guide.
Your files are kept
- Files you add to the folder, files you edit, other skills, and
AGENTS.mdare never overwritten or deleted. An edited file stops being updated and the build warns (MGSSKILL003). - An existing
muslim-genericserviceskill that the package did not create is left alone (MGSSKILL003). - If anything blocks writing (read-only checkout, a file where a folder should be, a damaged
manifest), the build warns (
MGSSKILL001) and continues. The guide never fails a build.
Upgrades and version conflicts
- When the package version changes, the next build replaces the files the package owns that you have not edited, and removes owned files the new version no longer ships (edited ones are kept).
- If projects in one repository use different versions, the folder keeps the highest version's
guide. A project on an older version leaves it untouched and warns (
MGSSKILL002). Align the versions to clear the warning. - Two different payloads published under the same version are not mixed; the installed one is kept
and the build warns (
MGSSKILL002). - Downgrading every project does not roll the guide back; delete the folder and build again.
- Parallel builds, several projects and several target frameworks write the folder one at a time (file lock) and do not conflict. Repeated builds do not rewrite unchanged files.
Removing it
Removing the package stops future updates but does not delete
.agents/skills/muslim-genericservice/; delete the folder yourself. dotnet clean does not remove
it either.
Turning it off
In the project file or in Directory.Build.props (for the whole repository):
<PropertyGroup>
<MuslimGenericServiceGenerateSkill>false</MuslimGenericServiceGenerateSkill>
</PropertyGroup>
or build with -p:MuslimGenericServiceGenerateSkill=false. Files already written are kept. The
switch affects only this package's guide. Other Muslim packages that ship a guide (for example
Muslim.Inject and Muslim.Validator, which arrive with this one) write their own folders and have
their own switches.
Other limitations
- Builds that skip the
Buildtarget (dotnet restorealone, tools that only evaluate projects) do not write the guide. - The copy step uses MSBuild's
RoslynCodeTaskFactory, which compiles a small task the first time each build process runs it. packages.configprojects do not importbuildTransitivefiles; usePackageReference.
Related packages
| Package | Use it for |
|---|---|
| Muslim.GenericService.Interface | The service interfaces |
| Muslim.GenericRepository | The repository implementation |
| Muslim.GenericRepository.Interface | The repository interfaces |
| Muslim.Result | Result<T> |
| Muslim.Validator | DTO validation |
| Muslim.Filter | Filtering, sorting and paging |
| Muslim.Inject | Automatic dependency registration |
License
See LICENSE.txt.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Muslim.GenericRepository.Interface (>= 10.0.1)
- Muslim.GenericService.Interface (>= 10.0.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Muslim.GenericService:
| Package | Downloads |
|---|---|
|
Muslim.LogInformation.Application
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
IService<TEntity> and its part interfaces moved to the new Muslim.GenericService.Interface package (same namespaces, type-forwarded); Service<TEntity> is split into partial files. Find(filter)/FindAsync(filter) no longer fail with "Missing map from X to X"; FindAsync page counts now count matching rows instead of the whole table; FindAsync(condition) returns a failed Result instead of throwing; DeleteRangeByIdsAsync and SoftDeleteRange* no longer report success as failure or carry a spurious "not found" error; CreateRange/CreateRangeAsync catch database errors; UpdateRange/UpdateRangeAsync enumerate once and detach every saved row; DTO validation uses the current Muslim.Inject request scope; a missing repository gives a descriptive error. Ships version-matched agent guidance and generates .agents/skills/muslim-genericservice during normal consuming builds; preserves user files and supports MuslimGenericServiceGenerateSkill=false. See CHANGELOG.md and README.md.