Developer forum

Forum » Development » 500 server error with a custom api

500 server error with a custom api

Fabio Monte
Reply

Hello

I'm encountering a 500 server error when setting up a custom api. The goal is to gather custom user info from a quiz and save it into a custom table we created but I may be missing a piece of the puzzle in the setup.

For this an api was registered:

namespace Quiz.App_Start
{
  public class QuizRegistration : APIRegistrationBase
  {
    protected override List<string> ControllerVersions => new List<string>()
    {
      nameof(QuizResultsController)
    };

    protected override string CurrentControllerVersion => nameof(QuizResultsController);

    protected override string ControllerName => "Quiz";
  }
}

The QuizResultsModel.cs:
namespace Quiz.Model
{
  public class QuizResultsModel
  {
    public int UserId { get; set; }
    public int Score { get; set; }
    public int SuccessCount { get; set; }
    public int FailCount { get; set; }
    public DateTime DateAttempted { get; set; }
    public TimeSpan TimeTaken { get; set; }
  }
}

QuizService.cs:
namespace Quiz.Service
{
  public class QuizService
  {
    public static ResponseStatus SaveQuizResult(QuizResultsModel quizResult)
    {
      ResponseStatus responseStatus = new ResponseStatus();
      string sql = @"INSERT INTO QuizResults (UserId, SuccessCount, FailCount, Score, DateAttempted, TimeTaken)
        VALUES (@UserId, @SuccessCount, @FailCount, @Score, @DateAttempted, @TimeTaken);
        SELECT SCOPE_IDENTITY();";

      try
      {
        using (var connection = new SqlConnection(Database.CreateConnection().ConnectionString))
        using (var command = new SqlCommand(sql, connection))
        {
          command.Parameters.AddWithValue("@UserId", quizResult.UserId);
          command.Parameters.AddWithValue("@SuccessCount", quizResult.SuccessCount);
          command.Parameters.AddWithValue("@FailCount", quizResult.FailCount);
          command.Parameters.AddWithValue("@Score", quizResult.Score);
          command.Parameters.AddWithValue("@DateAttempted", quizResult.DateAttempted);
          command.Parameters.AddWithValue("@TimeTaken", quizResult.TimeTaken);

          connection.Open();
          var quizResults = command.ExecuteScalar();
          responseStatus.HttpStatusCode = HttpStatusCode.OK;
          responseStatus.HttpStatusMessage = "Quiz result saved successfully " + quizResults;
        }
      }
      catch (Exception ex)
      {
        responseStatus.HttpStatusCode = HttpStatusCode.InternalServerError;
        responseStatus.HttpStatusMessage = ex.Message;
      }

      return responseStatus;
    }
  }
}

QuizResultsController.cs:

namespace Quiz.Controllers
{
  [RoutePrefix("someapi/Quiz")]
  public class QuizResultsController : ApiController
  {
    [HttpPost]
    [Route("SaveQuizResults")]
    public IHttpActionResult SaveQuizResults(QuizResultsModel quizResult)
    {
      var result = QuizService.SaveQuizResult(quizResult);
      return Ok(result);
    }
  }
}

The client side code that makes the request to the api:

function saveQuizMetricsData(){
fetch('/dwapi/Quiz/SaveQuizResults', {
    method: 'POST',
    body: JSON.stringify({
        QuizId: 1,
        UserId: 2,
        SuccessCount: 1,
        FailCount: 0,
        Score: 75,
        DateAttempted: '10/23/2024',
        TimeTaken: '01:22'
    }),
    headers: {
        'Content-Type': 'application/json'
    },
})
.then(response =>  response.json())
    .then((data) => {
        console.log(data)
    })
.catch(error => {
    console.log(error)
})
.finally(() => {
    console.log('data saved into database')
});

 It's the fetch resource that is causing the 500 server error, so the api may not be properly registered or I haven't set up this correctly and would like to get more insights on how to do it.


Replies

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

And what is the error?

 
Fabio Monte
Reply

It's returning "Failed to load resource: the server responded with a status of 500 ()  There is a problem with the resource you are looking for..." https://localhost/dwapi/Quiz/SaveQuizResults)

I've looked into the logs or the event viewer but there weren't anything related to what is causing the issue, but pointing to an issue with the resource may seem like it isn't properly set up?

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

If it's a 500 error, I think that means that the controller works and is throwing an error. Did you try debugging the action method and see what QuizService.SaveQuizResult does?

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

I noticed you have placed a custom controller under /dwapi route - that is not advised. Place it under /customapi or something specific your project. 

 
Fabio Monte
Reply

Sorry for the late reply, just got back into this.

So the "connection" variable in the service was returning a string without the password "User Id=username;Initial Catalog=dbname;Server=myserver;Min Pool Size = 5; Max Pool Size=200;" and the SSMS logs were registering a failed login for my user. Isn't this coming from what's stored in the Database > Setup > Settings?

Initially parameterized queries were implemented to prevent Sql injection but we changed it to hardcoded queries but I'm not so sure this should be kept or not in case DW handles it.

Here's the current code, which is working fine and saving to the database:
 

public static ResponseStatus SaveQuizResult(QuizResults quizResult)
{
    ResponseStatus responseStatus = new ResponseStatus();
    string sql = $@"INSERT INTO QuizResults (UserId, Score, SuccessCount, FailCount, TimeTaken, CourseId)
               VALUES ('{quizResult.UserId}', '{quizResult.Score}', '{quizResult.SuccessCount}', '{quizResult.FailCount}', '{quizResult.TimeTaken}', '{quizResult.CourseId}')";

    try
    {
        Database.ExecuteScalar(sql);
        responseStatus.HttpStatusCode = HttpStatusCode.OK;
        responseStatus.HttpStatusMessage = "Quiz result saved successfully ";
    }
    catch (Exception ex)
    {
        responseStatus.HttpStatusCode = HttpStatusCode.InternalServerError;
        responseStatus.HttpStatusMessage = ex.Message;
    }

    return responseStatus;
}
 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

I think ExecuteScalar goes against the database directly, so this code may be open to SQL Injection attacks. You can use an overload that accepts a CommandBuildder and then use CommandBuilder.Create.

Imar

 

 

You must be logged in to post in the forum