3

I thought I had resolved my access issues to my ServiceStack web service in this question, but I'm now getting the same 'Access is denied' errors even with the fixes found in that solution and haven't been able to resolve them on my own.

Here's where I'm at with this: I've got a web service that I am sending data to using a POST method. I also have a GET method that returns the same response type as the POST, and that works fine. As far as I can tell, the request isn't even getting to ServiceStack before it fails. There are no Access-Control headers in the response, even though I'm using the CorsFeature plugin in my response headers. I can't figure out why it's not getting to any ServiceStack code though... Everything seems to be setup correctly. BTW, when I try the DELETE action I get a "403 Forbidden, Write access is denied" error from the server, if that's helpful at all?

Here's my Global.asax (pertinent sections):

public class AppHost : AppHostBase
{
    public AppHost() : base("RMS Citations Web Service", typeof(CitationService).Assembly) { }

    public override void Configure(Container container)
    {
        SetConfig(new EndpointHostConfig
        {
            DefaultContentType = ContentType.Json,
            ReturnsInnerException = true,
            WsdlServiceNamespace = "http://www.servicestack.net/types"
        });

        Plugins.Add(new CorsFeature());
        RequestFilters.Add((httpReq, httpRes, requestDto) =>
        {
            if (httpReq.HttpMethod == "OPTIONS")
                httpRes.EndRequestWithNoContent(); //   extension method                    
        });

        container.RegisterAutoWired<CitationRequest>();

        // Not sure I need this - is it necessary for the Funq container?
        using (var addCitation = container.Resolve<CitationService>())
        {
            addCitation.Post(container.Resolve<CitationRequest>());
            addCitation.Get(container.Resolve<CitationRequest>());
            addCitation.Delete(container.Resolve<CitationRequest>());
        }
    }
}

protected void Application_Start(object sender, EventArgs e)
{
    new AppHost().Init();
}

Here's my request and response classes:

[Route("/citations", "POST, OPTIONS")]
[Route("/citations/{ReportNumber_Prefix}/{ReportNumber}/{AgencyId}", "GET, DELETE, OPTIONS")]
public class CitationRequest : RmsData.Citation, IReturn<CitationResponse>
{
    public CitationStatus Status { get; set; }
}

public enum CitationStatus
{
    COMP,
    HOLD
}

public class CitationResponse
{
    public bool Accepted { get; set; }
    public string ActivityId { get; set; }
    public int ParticipantId { get; set; }
    public string Message { get; set; }
    public Exception RmsException { get; set; }
}

Here's my Service class:

public class CitationService : Service
{
    public Repository Repository { get { return new Repository(); } }

    public CitationResponse Post(CitationRequest citation)
    {
        var response = new CitationResponse { Accepted = false };

        if (string.IsNullOrEmpty(citation.ReportNumber))
        {
            response.Accepted = false;
            response.Message = "Report number was empty, so no data was sent to the web service.";
            return response;
        }

        try
        {
            response.ActivityId = Repository.CreateCitation(citation.ReportNumber, citation.ReportNumber_Prefix, citation.ViolationDateTime, citation.AgencyId, citation.Status);
            response.Accepted = true;
        }
        catch (Exception ex)
        {
            response.Accepted = false;
            response.Message = ex.Message;
            response.RmsException = ex;
        }

        return response;
    }

    public CitationResponse Get(CitationRequest citation)
    {
        var citationResponse = new CitationResponse();
        if (string.IsNullOrEmpty(citation.ReportNumber))
        {
            citationResponse.Accepted = false;
            citationResponse.Message = "Error occurred passing citation data to web service.";
            return citationResponse;
        }

        var isDuplicate = Repository.IsDuplicateReportNumber(citation.AgencyId, citation.ReportNumber, citation.ReportNumber_Prefix);
        citationResponse = new CitationResponse
        {
            Accepted = isDuplicate,
            Message =
                isDuplicate ? "Report Number already exists in database." : "Report Number has not yet been used."
        };

        return citationResponse;
    }

    public CitationResponse Delete(CitationRequest citation)
    {
        var citationResponse = new CitationResponse();
        try
        {
            if (Repository.DeleteCitation(citation.ReportNumber, citation.AgencyId, citation.ReportNumber_Prefix))
            {
                citationResponse.Accepted = true;
                citationResponse.Message = "Citation removed from RMS successfully.";
            }
            else
            {
                citationResponse.Accepted = false;
                citationResponse.Message = "Citation NOT deleted from RMS.  Check exception for details.";
            }
        }
        catch (Exception ex)
        {
            citationResponse.Accepted = false;
            citationResponse.Message = ex.Message;
            citationResponse.RmsException = new Exception(ex.Message);
            throw;
        }

        return citationResponse;
    }
}

Finally, here's how I send the data to the web service. It always goes right to the error block:

SendCitationToDb: function (cit, callback) {
    $.ajax({
        type: "POST",
        url: Citations.DataServiceUrl + "citations",
        data: JSON.stringify(cit),
        contentType: "application/json",
        dataType: "json",
        success: function(data) {
            if (!data.Accepted) {
                Citations.ShowMessage('Citation not added', 'Citation not added.  Error was: ' + data.Message, 'error');
            } else {
                ActivityId = data.ActivityId;
                callback(data);
            }
        },
        error: function(errMsg) {
            Citations.ShowMessage('Citation not added', 'Citation not added.  Error was: ' + errMsg.statusText, 'error');
        }
    });
}

Here's a sample output from Chrome dev tools. First a good response from this service (GET): enter image description here

Updated response after adding aspnet_isapi.dll path to wildcards in IIS:: (removed screenshot)

Update 2 - That is the POST response. The request shows it's the POST method, but the code jumps right into the error block in the jQuery ajax function. In the dev tools I see this line: enter image description here

Then I click it and get these request and response headers: enter image description here

Not sure what else to look for - I know it says Status Code 200 OK, but I think that's just for the pre-flight OPTIONS...? Not sure, but it doesn't return a valid response from the service.

Your help is greatly appreciated!

Community
  • 1
  • 1
Eddie
  • 1,228
  • 3
  • 17
  • 31

1 Answers1

1

It looks like WebDav is handling and rejecting your request. You can try disabling WebDav to see if it helps.

Community
  • 1
  • 1
mythz
  • 141,670
  • 29
  • 246
  • 390
  • Thanks @mythz - just tried that, but I get the same response from server. The only solution of the ones listed on that link that I tried was the web.config entry. Not sure how to implement the others...? From the response, it looks like WebDAV is not disabled, and is still handling the request... – Eddie Sep 30 '13 at 18:53
  • Ok, I went in and manually prohibited WebDAV in IIS on that server. Now when I run the same request I still get the same error, but the request does not include the DAV entries: Allow:OPTIONS, TRACE, GET, HEAD Content-Length:0 Date:Mon, 30 Sep 2013 18:57:50 GMT Public:OPTIONS, TRACE, GET, HEAD, POST Server:Microsoft-IIS/6.0 X-Powered-By:ASP.NET – Eddie Sep 30 '13 at 18:59
  • If the response headers doesn't contain `X-Powered-By: ServiceStack..` than the request hasn't reached ServiceStack, something else hijacking it. I'd look for issues relating to `IIS6 DELETE 403` like [this](http://serverfault.com/a/47937/144494). – mythz Sep 30 '13 at 19:30
  • Ok, now we're getting somewhere. I added my aspnet_isapi.dll path to the wildcards section in IIS and now my DELETE action works. Unfortunately my POST is still not working, but the response headers do include ServiceStack, so at least I'm reaching the code. Can't tell much else based on the response though... (See updated response screenshot above) – Eddie Sep 30 '13 at 19:57
  • @Eddie they both look `200 OK`? do you have a screenshot of the **POST** error response? – mythz Sep 30 '13 at 20:19
  • I posted updated screenshots above, but the response is the same... Not sure, but that's what I get when I send a POST to the service. See my comments below the updated screens above. I get the same thing in IE and Chrome, if that makes any difference? Thanks again for your help! – Eddie Sep 30 '13 at 21:08
  • Ok, got it working, had to clean a couple things up. It's working now. Seems that adding the aspnet_isapi.dll to the wildcards path was what got it working for me. Thanks again for your help mythz! – Eddie Sep 30 '13 at 21:27
  • @Eddie Great, glad to hear it :) – mythz Sep 30 '13 at 21:27