简体   繁体   中英

Route to specific id in angular2/.net core

I'm having trouble getting routing in Angular2/.Net Core to work properly.

I've started a default .Net Core web project with Angular, and have successfully created a new controller with the applicable view components. The page's purpose is to display a list of documents and give you the option to click the title to see each document in a separate view.

So long everything works, it displays the contents of the page and I can also display a list of documents retrieved from the database. The routing looks like this:

@NgModule({
    declarations: [
        AppComponent,
        NavMenuComponent,
        DocumentsComponent,
        HomeComponent
    ],
    imports: [
        CommonModule,
        HttpModule,
        FormsModule,
        RouterModule.forRoot([
            { path: '', redirectTo: 'home', pathMatch: 'full' },
            { path: 'home', component: HomeComponent },
            { path: 'documents', component: DocumentsComponent },
            { path: '**', redirectTo: 'home' }
        ])
    ]
})
export class AppModuleShared {
}

I have a link on each document so that when you click it you are transferred from the list /documents to eg. /documents/1

When I click on a link it only stays there long enough so I can see the URL change and then it goes to the default fallback /home .

In Startup.cs I have the default route handling set:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
    routes.MapSpaFallbackRoute(
        name: "spa-fallback",
        defaults: new { controller = "Home", action = "Index" });
});

From what I can tell the "default" map route should pick up /documents/1 but it doesn't. I never even gets to the backend method for the route.

[Produces("application/json")]
[Route("api/[controller]")]
public class DocumentsController : Controller
{
    private readonly DatabaseContext _context;

    public DocumentsController(DatabaseContext context)
    {
        _context = context;
    }

    // GET: api/Documents
    [HttpGet]
    public IActionResult GetDocuments()
    {
        // returns a JSON list of documents, works fine
    }

    // GET: api/Documents/5
    [HttpGet("{id}")]
    public async Task<IActionResult> GetDocument([FromRoute] int id)
    {
        //returns the specified document, is never even called
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var document = await _context.Documents.SingleOrDefaultAsync(m => m.Id == id);

        if (document == null)
        {
            return NotFound();
        }

        return Ok(document);
    }

What do I need to do to get the specific routes to work?

From what I can tell the "default" map route should pick up /documents/1 but it doesn't.

Nope. The default route isn't configured that way. You must supply the action method name as the second parameter to match the default route.

/documents/getdocument/1

That said, it won't work. When you add an attribute route it automatically blocks the above route.

Therefore, the only URL that will work to get to DocumentsController.GetDocument(int) is:

/api/documents/1

This is because you are defining [Route("api/[controller]")] on your controller which makes every action in the controller prefixed this way.

If you want /documents/1 to be the URL and use attribute routing, you can use:

[Produces("application/json")]
[Route("documents")]
public class DocumentsController : Controller
{
    private readonly DatabaseContext _context;

    public DocumentsController(DatabaseContext context)
    {
        _context = context;
    }

    // GET: api/Documents
    [HttpGet(Order = 2)]
    public IActionResult GetDocuments()
    {
        // returns a JSON list of documents, works fine
    }

    // GET: api/Documents/5
    [HttpGet("{id}", Order = 1)]
    public async Task<IActionResult> GetDocument([FromRoute] int id)
    {
        //returns the specified document, is never even called
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var document = await _context.Documents.SingleOrDefaultAsync(m => m.Id == id);

        if (document == null)
        {
            return NotFound();
        }

        return Ok(document);
    }
}

Or if you want to use convention based routing, remove the [Route] attribute from the controller, URL templates and Order from HttpGet above each action method and use:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "documents",
        template: "documents/{id?}",
        defaults: new { controller = "Documents", action = "GetDocuments" });

    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

You need to tell the angular router that there is more after the documents part of the path. It's looking for a component matched to the route /documents/1 and not finding it. If you add /:id to your path it should allow it to map the second part of your url to a route instead of redirecting to home

{ path: 'documents/:id', component: DocumentsComponent },

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM