ServiceStack: Null Exception when using HttpResponse - servicestack

I have been loving the clean conventions in ServiceStack however I recently ran into a vexing problem. The user loads a "create" page to create an "ad", then posts the form data. The server in term should process the posted data and redirect the user upon success.
I run this with the debugger. The POST method completes without error, but the server always returns the error after the service is finished:
Object reference not set to an instance of an object. AT
CompiledRazorTemplates.Dynamic.dfdcdedabeabca.Execute() at ServiceStack.Razor.Templating.TemplateService.ExecuteTemplate[T](T model, String name, String defaultTemplatePath, IHttpRequest httpReq, IHttpResponse httpRes) at ServiceStack.Razor.RazorFormat.ProcessRazorPage(IHttpRequest httpReq, ViewPageRef razorPage, Object dto, IHttpResponse httpRes) at ServiceStack.Razor.RazorFormat.ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, Object dto) at ServiceStack.WebHost.Endpoints.Formats.HtmlFormat.<>c__DisplayClass1.<SerializeToStream>b__0(IViewEngine x) at System.Linq.Enumerable.Any[TSource](IEnumerable1 source, Func2 predicate) at ServiceStack.WebHost.Endpoints.Formats.HtmlFormat.SerializeToStream(IRequestContext requestContext, Object response, IHttpResponse httpRes) at ServiceStack.Common.Web.HttpResponseFilter.SerializeToStream(IRequestContext requestContext, Object response, Stream responseStream) at ServiceStack.Common.Web.HttpResult.WriteTo(Stream responseStream) at ServiceStack.WebHost.Endpoints.Extensions.HttpResponseExtensions.WriteToOutputStream(IHttpResponse response, Object result, Byte[] bodyPrefix, Byte[] bodySuffix) at ServiceStack.WebHost.Endpoints.Extensions.HttpResponseExtensions.WriteToResponse(IHttpResponse response, Object result, ResponseSerializerDelegate defaultAction, IRequestContext serializerCtx, Byte[] bodyPrefix, Byte[] bodySuffix)
Ive boiled the code down to this to isolate the issue:
[Route("/ad/create", Verbs = "GET")]
public class AdCreateViewModelCriteria
{
}
[Route("/ad/create", Verbs = "POST")]
public class AdCreate
{
//some things
}
public class AdCreateService:Service
{
//the error occurs AFTER this method is complete
public object Post(AdCreate ac)
{
try
{
//do some stuff
return new HttpResult()
{
StatusCode = HttpStatusCode.Redirect,
Headers ={{HttpHeaders.Location, "/home"}}
};
}
catch (Exception e)
{
return new HttpResult(e)
{
StatusCode = HttpStatusCode.InternalServerError
};
}
}
[DefaultView("adcreate")]
public object Get(AdCreateViewModelCriteria criteria)
{
return AdCreateViewModel.Load(criteria,Db);
}
}

Related

How to access api.openrouteservice.org through Androids Volley package

I want to access data on the openrouteservice API - specifically the distance between two given coordinates on the globe - from my Android application.
I have made requests and gotten viable responses from another API that converts two given addresses into their latlong coordinates using the same style of code this request is trying to execute. It works fine, the coordinates arrive and i can further utilize them no problem.
My problem is that i seem to be accessing the API wrongly because if I Log the URL as seen below and copy it from the Debug window into my browser it sends the request, gets a response and shows it in the browser window.
But my application doesn't recieve a response from the API as the onResponse code bit is never executed and the "Fetch done" Log never appears in the actual Debug Log.
The following is my setup of code, which uses Volley to access HTTP Requests and which works fine for other APIs.
#Override
protected String doInBackground(String... strings) {
Log.d("Run =>","Query 3");
String targetKoordURL = null;
String startKoordURL = null;
try {
startKoordURL = startK.getString("lon").concat(",").concat(startK.getString("lat"));
targetKoordURL = targetK.getString("lon").concat(",").concat(targetK.getString("lat"));
} catch (JSONException e) {
e.printStackTrace();
}
String URLfin = "https://api.openrouteservice.org/v2/directions/driving-car?api_key=5b3ce3597851110001cf624823e587e7a80c4c6ab02af6d394585213&start="+startKoordURL+"&end="+targetKoordURL;
Log.d("Debug =>", URLfin);
JsonObjectRequest req = new JsonObjectRequest(Request.Method.GET, URLfin, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
store = response;
Log.d("Run =>", "Fetch done!");
continueImp();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if(error instanceof TimeoutError || error instanceof NoConnectionError){
sideFetcherHTTPRequestStart replace = new sideFetcherHTTPRequestStart();
replace.execute();
Log.d("VOLLEY_ERROR", "Retrying on Kilometer request");
}
error.printStackTrace();
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Accept", "application/json,application/geo+json,application/gpx+xml,img/png; charset=utf-8");
return params;
}
};
return null;
}
You forget to add the request to request queue, try to do as following:
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest req = new JsonObjectRequest(/*params*/);
//add above request to queue
queue.add(req);

Spring integration, Setting error-handler on http outbound gateway

If I add a custom error-handler to an int-http:outbound-gateway, the response body is not unmarshalled according to the expected-response-type, instead I only get a ResponseEntity returned. My custom error handler is pretty simple:
public class MyResponseErrorHandler extends DefaultResponseErrorHandler {
private static final Logger log = LoggerFactory.getLogger(AlmaGetUserResponseErrorHandler.class);
#Override
public boolean hasError(final ClientHttpResponse response) throws IOException {
// stop http 400 from returning true to error here.
log.debug("Request has returned error code {}", response.getStatusCode());
if (response.getBody() != null) {
String returnBody = IOUtils.toString(response.getBody(), "UTF-8");
log.debug("Checking error from response, code {}, body {}", response.getStatusCode(), returnBody);
}
return false;
}
}
As soon as I remove the error-handler, it unmarshalls the XML response into my POJO correctly.
The issue above was that the MyResponseErrorHandler class was streaming out the body content before it was being passed to the marshaller for expected-response-type. Hence the body was null and a plain ResponseEntity was returned.

How to log ServiceStack.Messaging.Message to a database with OrmLite?

Given the following code:
public class AppHost : BasicAppHost
{
public AppHost()
: base(typeof(LeadService).Assembly){}
public override void Configure(Container container)
{
SetConfig(new HostConfig
{
DebugMode = ConfigUtils.GetAppSetting<bool>("DebugMode:Enabled", false)
});
//DataAccess
//Set ORMLite to work with columns like ColumnLikeThis
PostgreSqlDialect.Provider.NamingStrategy = new OrmLiteNamingStrategyBase();
//Set ORMLite to use ServiceStack.Text for JSON serialization
PostgreSqlDialect.Provider.StringSerializer = new JsonStringSerializer();
var dbFactory = new OrmLiteConnectionFactory(ConfigUtils.GetConnectionString("Lead:Default"), PostgreSQLDialectProvider.Instance);
container.Register<IDbConnectionFactory>(dbFactory);
//RabbitMQ
container.Register<IMessageService>(c => new RabbitMqServer()
{
AutoReconnect = true,
DisablePriorityQueues = true,
});
var mqServer = container.Resolve<IMessageService>();
//Handlers
container.Register<IMessageHandlers>(c => new MessageHandlers(c.Resolve<IDbConnectionFactory>()));
var handlers = container.Resolve<IMessageHandlers>();
mqServer.RegisterHandler<LeadInformation>(handlers.OnProcessLeadInformation, handlers.OnExceptionLeadInformation);
mqServer.Start();
}
}
public class MessageHandlers : IMessageHandlers
{
private readonly ILog _log = LogManager.GetLogger(typeof(MessageHandlers));
private readonly IDbConnectionFactory _connectionFactory;
public MessageHandlers(IDbConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public object OnProcessLeadInformation(IMessage<LeadInformation> request)
{
var sw = Stopwatch.StartNew();
try
{
// Log to the database
using (var db = _connectionFactory.OpenDbConnection())
{
db.CreateTableIfNotExists<Message>();
var msg = request as Message<LeadInformation>; // Anyway not to have to cast it?
db.Save(msg); // Does not work
}
// Run rules against lead
// Log response to database
// return response
}
catch (Exception exception)
{
_log.Error(request, exception);
}
return new LeadInformationResponse
{
TimeTakenMs = sw.ElapsedMilliseconds,
Result = "Processed lead {0}".Fmt(request.GetBody().LeadApplication.LastName)
};
}
public void OnExceptionLeadInformation(IMessage<LeadInformation> request, Exception exception)
{
_log.Error(request, exception);
}
}
Is it possible to persist the whole message? The table gets created, and I was able to save one message, and that's it no more saves with different messages.
Update
Turns out I'm getting an exception during the save operation
Npgsql.NpgsqlException was caught
_HResult=-2147467259
_message=ERROR: 42P01: relation "Message1" does not exist
HResult=-2147467259
IsTransient=false
Message=ERROR: 42P01: relation "Message1" does not exist
Source=Npgsql
ErrorCode=-2147467259
BaseMessage=relation "Message1" does not exist
Code=42P01
ColumnName=""
ConstraintName=""
DataTypeName=""
Detail=""
ErrorSql=SELECT "Id", "CreatedDate", "Priority", "RetryAttempts", "ReplyId", "ReplyTo", "Options", "Error", "Tag", "Body" FROM "Message1" WHERE "Id" = (('ab297bca-5aea-4886-b09b-5a606b0764d5')::uuid)
File=src\backend\parser\parse_relation.c
Hint=""
Line=986
Position=119
Routine=parserOpenTable
SchemaName=""
Severity=ERROR
TableName=""
Where=""
StackTrace:
at Npgsql.NpgsqlState.d__0.MoveNext()
at Npgsql.ForwardsOnlyDataReader.GetNextResponseObject(Boolean cleanup)
at Npgsql.ForwardsOnlyDataReader.GetNextRowDescription()
at Npgsql.ForwardsOnlyDataReader.NextResultInternal()
at Npgsql.ForwardsOnlyDataReader..ctor(IEnumerable1 dataEnumeration, CommandBehavior behavior, NpgsqlCommand command, NotificationThreadBlock threadBlock, Boolean preparedStatement, NpgsqlRowDescription rowDescription)
at Npgsql.NpgsqlCommand.GetReader(CommandBehavior cb)
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior cb)
at Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
at ServiceStack.OrmLite.OrmLiteReadExtensions.ExecReader(IDbCommand dbCmd, String sql)
at ServiceStack.OrmLite.OrmLiteResultsFilterExtensions.ConvertTo[T](IDbCommand dbCmd, String sql)
at ServiceStack.OrmLite.OrmLiteReadExtensions.SingleById[T](IDbCommand dbCmd, Object value)
at ServiceStack.OrmLite.OrmLiteWriteExtensions.Save[T](IDbCommand dbCmd, T obj)
at ServiceStack.OrmLite.OrmLiteWriteConnectionExtensions.<>c__DisplayClass5a1.b__58(IDbCommand dbCmd)
at ServiceStack.OrmLite.OrmLiteExecFilter.Exec[T](IDbConnection dbConn, Func2 filter)
at ServiceStack.OrmLite.ReadConnectionExtensions.Exec[T](IDbConnection dbConn, Func2 filter)
at ServiceStack.OrmLite.OrmLiteWriteConnectionExtensions.Save[T](IDbConnection dbConn, T obj, Boolean references)
at LO.Leads.Processor.ServiceInterface.MessageHandlers.OnProcessLeadInformation(IMessage`1 request) in e:\Lead\src\LO.Leads.Processor\LO.Leads.Processor.ServiceInterface\MessageHandlers.cs:line 41
Update 2
Turns out my cast was wrong, this now works
using (var db = _connectionFactory.OpenDbConnection())
{
db.CreateTableIfNotExists<Message>();
db.Save(request as Message);
}
Thank you,
Stephen
You have to cast the IMessage back to a Message DTO in order for it to work. e.g.
using (var db = _connectionFactory.OpenDbConnection())
{
db.CreateTableIfNotExists<Message>();
db.Save(request as Message);
}

How would I change a ServiceStack response DTO

I'm working on an API where I'd like to be able to customize the response structure based on a parameter from the client. Response filters seem like a good place to do this in order to avoid doing so in each service or action. The problem is that while I have access to the response DTO returned by the action, and could change its properties, I can't find how or where to replace the object entirely.
Naively replacing the object in the response filter did not work, but this help illustrate what I'm trying to do:
public class ChangeResponseAttribute : ResponseFilterAttribute
{
public override void Execute(IHttpRequest req, IHttpResponse res, object responseDto)
{
var overrideText = req.QueryString["override"];
if (!String.IsNullOrEmpty(overrideText))
responseDto = new { Message = overrideText };
}
}
[ChangeResponse]
public class TodosService : Service
{
public object Get(Todos request)
{
return new object[0];
}
}
It looks like another option would be to write the custom response directly & end the request, but that would bypass any other processing left to do by ServiceStack.
Is there a better place to do this than a response filter? Or do I need to bite the bullet and return the optimal DTO in each action?
You can't change the Response DTO in a filter, but yes one option is to write the response in the filter itself (see this answer for an example of how to do this).
The other option is to use a ServiceRunner and override the OnAfterExecute() custom hook which does let you modify the response returned, e.g:
public class MyServiceRunner<T> : ServiceRunner<T>
{
public override object OnAfterExecute(
IRequestContext requestContext, object response)
{
// Called just after any Action is executed
var overrideText = req.Get<IHttpRequest>().QueryString["override"];
return !string.IsNullOrEmpty(overrideText)
? new { Message = overrideText } : null;
}
}
To get ServiceStack to use it you need to override the CreateServiceRunner method in your AppHost, e.g:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext);
}

ServiceExceptionHandler usage on RestServiceBase<T>

I'm trying to use the ServiceExceptionHandler on my Serivce which extends RestServiceBase<TViewModel>
I can use the AppHost.ServiceExceptionHandler, that's working fine. I need the user info from the HttpRequest, thats not available at AppHost level.
So I'm trying to use the ServiceExceptionHandler on Service level. Though I set the delegate on service ctor, it's null when exception thrown on OnGet method
public class StudentService : RestServiceBase<Student>
{
public StudentService()
{
ServiceExceptionHandler = (request, exception) =>
{
logger.Error(string.Format("{0} - {1} \n Request : {2}\n", HttpRequest.UserName(), exception.Message, request.Dump()), exception);
var errors = new ValidationErrorField[] { new ValidationErrorField("System Error", "TODO", "System Error") };
return DtoUtils.CreateErrorResponse("System Error", "System Error", errors);
};
}
}
I'm not sure of what is the issue with this code. Any help will be appreciated.
Register Global AppHost.ServiceExceptionHandler
In your AppHost.Configure() you can register a global Exception handler with:
this.ServiceExceptionHandler = (request, ex) => {
... //handle exception and generate your own ErrorResponse
};
For finer-grained Exception handlers you can override the following custom service event hooks:
Handling Exceptions with the New API
If you're using the New API you can override the Exception by providing a custom runner, e.g:
public class AppHost {
...
public virtual IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
ActionContext actionContext)
{
//Cached per Service Action
return new ServiceRunner<TRequest>(this, actionContext);
}
}
public class MyServiceRunner<T> : ServiceRunner<T> {
public override object HandleException(
IRequestContext requestContext, TRequest request, Exception ex) {
// Called whenever an exception is thrown in your Services Action
}
}
Handling Exceptions with the Old API
RestServiceBase<T> is uses the old API in which you can handle errors by overriding the HandleException method, e.g:
public class StudentService : RestServiceBase<Student>
{
...
protected override object HandleException(T request, Exception ex)
{
LogException(ex);
return base.HandleException(request, ex);
}
}

Resources