I have a RESTier Website using the latest version. All my entities and views I created from the database with EF 6 work fine, but I cannot seem to get the stored procedures I brought in to work. As the documentation is a little sparse I'm not sure if I need to implement anything beyond to basic startup of the service.
When sending this URI via Postman I get a 404 error not found:
http://192.168.1.20:60666/api/MIC_REST/up_BomAssemParts_s_ByJobID_FmNumber_WorkArea_TEST(jobID=252, fmNumber= 98, workAreas='A13,D12,A3,A9,A7,A10')
I basically have stock setup of service below. Any help in whether it might be the URI or the setup would be greatly appreciated.
WebApiConfig:
public static class WebApiConfig
{
public async static void Register(HttpConfiguration config)
{
config.EnableSystemDiagnosticsTracing();
config.Filter().Expand().Select().OrderBy().MaxTop(1000).Count();
await config.MapRestierRoute<EntityFrameworkApi<MICdB>>(
"MIC_REST", "api/MIC_REST", new Microsoft.Restier.Publishers.OData.Batch.RestierBatchHandler(GlobalConfiguration.DefaultServer));
}
}
public virtual ObjectResult<up_BomAssemParts_s_ByJobID_FmNumber_WorkArea_Result_TEST> up_BomAssemParts_s_ByJobID_FmNumber_WorkArea_TEST( Nullable<int> jobID, Nullable<int> fmNumber, string workAreas)
{
var jobIDParameter = jobID.HasValue ?
new ObjectParameter("JobID", jobID) :
new ObjectParameter("JobID", typeof(int));
var fmNumberParameter = fmNumber.HasValue ?
new ObjectParameter("FmNumber", fmNumber) :
new ObjectParameter("FmNumber", typeof(int));
var workAreasParameter = workAreas != null ?
new ObjectParameter("WorkAreas", workAreas) :
new ObjectParameter("WorkAreas", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<up_BomAssemParts_s_ByJobID_FmNumber_WorkArea_Result_TEST>("up_BomAssemParts_s_ByJobID_FmNumber_WorkArea_TEST", jobIDParameter, fmNumberParameter, workAreasParameter);
}
public partial class up_BomAssemParts_s_ByJobID_FmNumber_WorkArea_Result_TEST
{
public string BomAssemShipMark { get; set; }
public string CurrentLocation { get; set; }
public int Quantity { get; set; }
public string PlPiecemark { get; set; }
public string MatSizeText { get; set; }
public string LengthText { get; set; }
public string GradeDescription { get; set; }
public string PlPiecemarkPrefix { get; set; }
public int PlPiecemarkSuffix { get; set; }
public string PlCodes { get; set; }
public string PlPremark { get; set; }
public Nullable<int> FmNumber { get; set; }
}
After banging my head on trying to get an ODataController to work, I have giving up and resorted to using an Apicontroller, which ended up being very simple to implement. With an ODataController, I could never get a URL to work or if I tried to add an oDataRoute, an error always resulted. It seems absurd that with all the fairly useless examples posted using ResTier the one real world example that one would expect (a stored procedure that returns a list of non-entity data for UI view purposes) seems non-existent. ResTier seems to work great for EntitySets but this mess I found myself in makes me question it (or Odata not sure where the fault is). Oh well, below gets the data...now to find a compress to fix the welt on my forehead....
[System.Web.Http.RoutePrefix("spapi/MIC_REST")]
public class SPController :ApiController
{
private MICdB db = new MICdB();
[System.Web.Http.Route("part/{jobID:int}/{fmNumber:int}/{workAreas}")]
// [EnableQuery]
public List<up_BomAssemParts_s_ByJobID_FmNumber_WorkArea_Result> GetPartsLists([FromODataUri]int jobID, [FromODataUri]int fmNumber, [FromODataUri]string workAreas)
{
return db.up_BomAssemParts_s_ByJobID_FmNumber_WorkArea_TEST(jobID, fmNumber, workAreas).ToList();
}
}
Related
I am currently developing a web api in .NET Core 3. I currently have the following model for my error response object:
public class ErrorRo
{
public string Message { get; set; }
public int StatusCode { get; set; }
public string Endpoint { get; set; }
public string Parameters { get; set; }
public string IpAddress { get; set; }
}
This is a mandated response I need to implement, management has pushed this. It allows more verbose error messages for people hitting our API so that they know what went wrong.
At the moment I am currently populating this object manually in the methods themselves. Is there a way where I can overwrite the response methods. I.e. can I override the BadRequest of IActionResult to automatically populate these fields?
Thanks!
You can use result filters for this purpose. Add a filter which repalces result before sending it back
Model
public class CustomErroModel
{
public string Message { get; set; }
public int StatusCode { get; set; }
public string Endpoint { get; set; }
public string Parameters { get; set; }
public string IpAddress { get; set; }
}
Filter
public class BadRequestCustomErrorFilterAttribute : ResultFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
//todo: check for BadRequestObjectResult if anything is returned for bad request
if (context.Result is BadRequestResult)
{
var result = new CustomErroModel
{
StatusCode = 200, //you status code
Endpoint = context.HttpContext.Request.GetDisplayUrl(),
Message = "some message",
IpAddress = context.HttpContext.Connection.RemoteIpAddress.ToString(), //find better implementation in case of proxy
//this returns only parameters that controller expects but not those are not defined in model
Parameters = string.Join(", ", context.ModelState.Select(v => $"{v.Key}={v.Value.AttemptedValue}"))
};
context.Result = new OkObjectResult(result); // or any other ObjectResult
}
}
}
Then apply filter per action or globally
[BadRequestCustomErrorFilter]
public IActionResult SomeAction(SomeModel model)
or
services
.AddMvc(options =>
{
options.Filters.Add<BadRequestCustomErrorFilterAttribute>();
//...
}
Well it depends on the scenario, but one possible approach could be to use a middleware using a similar strategy like the one described in this question, so that you complete the response with extra information.
This is a C# Question, using .NET framework built on Asp.NET Boilerplate.
Again, to re-emphasis the question being asked is "HOW...", so if an answer that was provided was a url link or a descriptive explanation on how something was supposed to be done, i would very much appreciate it. (Dont answer questions on how to tie shoelace by showing a picture of a tied shoe, nor do you answer "how to fish" by showing a recording of someone fishing...)
Since the question is pretty basic (i don't need to rephrase/repeat the header again), i'll give an example.
If i have a Forum service, and i create a class to load a Thread. Inside that thread class should be some sort of collection, array, list, or even a dbset of Post that is pulled on construct.
[Table("Thread", Schema = "dbo")]
public class ThreadModel
{
[Key]
public long Id { get; set; }
public string Title { get; set; }
//Idea 1
//Value should automatically be pulled and cached the moment class connects to database
public Post[] Posts { get; set; }
//Idea 2
//Post has a constructor to return all post that matches a thread id. While new tag keeps the return value constantly refreshed.
public Post[] Posts { get { return new Post(this.Id) } }
//Idea 3
//Not sure how collection is supposed to work. Does it automatically just pull or will i need to make a method to request?
public virtual ICollection<Post> Posts { get; set; }
//Example constructor
//When connected to database key-value pairs that match database labels will automatically get stored in class
protected ThreadModel()
{
//Idea 1-A
//Should be a value of null or empty if database yields no results
Posts = new Post();
}
public ThreadModel(int threadid) : this()
{
//Idea 1-A
Id = threadid;
//new Post => returns all posts in db
//Posts default value is all post in db
Posts = Posts.Select(post => post.threadid == this.id)
//Idea 3-A
Posts = Posts.Get(post => post.threadid == this.id)
//Idea 4
Posts = new Posts().GetThread(threadid);
}
}
Side questions
If all entities are created by inheriting Entity then at what point am i exposed to EntityFramework and DbContext?
I love this example here, submitted by a user as they attempt to connect ABP to their database. But their example doesn't show parent/child resources. I'm unable to find the guide they used to create that, and how it relates back to using ABP to fetch EntityFramework's DbContext example
How does this work? I'm unable to find instructions or explanation for this? (What am i to enter into google to get answers on these mechanics?)
[Table("AbpItems")]
public class Item : Entity
{
[ForeignKey("PostId")]
public Post Post { get; set; }
public int PostId { get; set; }
}
How does this integrate into/with abp's EntityFramework?
Where am i supposed to be creating my Database Table/Class? The project follows the Core.csproj, Application.csproj, and EntityFramework.csproj assembly layout. But it seems like every example is creating the classes at different stages or locations of the solution.
use GetAllIncluding. See https://github.com/aspnetboilerplate/aspnetboilerplate/issues/2617
Here's a complete solution ;
namespace EbicogluSoftware.Forum.Threads
{
[Table("Threads")]
public class Thread : FullAuditedEntity
{
[Required]
[StringLength(500)]
public virtual string Title { get; set; }
[Required]
[StringLength(2000)]
public virtual string Text { get; set; }
public virtual List<Post> Posts { get; set; }
public Thread()
{
Posts = new List<Post>();
}
}
[Table("Posts")]
public class Post : FullAuditedEntity
{
[Required]
[StringLength(2000)]
public virtual string Text { get; set; }
}
public class ThreadDto
{
public string Title { get; set; }
public string Text { get; set; }
public List<PostDto> Posts { get; set; }
public ThreadDto()
{
Posts = new List<PostDto>();
}
}
public class PostDto
{
public string Text { get; set; }
}
public class ThreadAppService : IApplicationService
{
private readonly IRepository<Thread> _threadRepository;
public ThreadAppService(IRepository<Thread> threadRepository)
{
_threadRepository = threadRepository;
}
public async Task<List<TenantListDto>> GetThreads()
{
var threads = await _threadRepository.GetAllIncluding(x => x.Posts).ToListAsync();
return threads.MapTo<List<TenantListDto>>();
}
}
}
Where am i supposed to be creating my Database Table/Class?
You can create them in YourProject.Core.proj
I want to use Automapper for mapping SOAP Web Service Response to a Model which will be used to return the result through a Web API.
Mostly of the attributes returned in the object by the web service are codes, we want to show in the response of our api the descriptions related to those codes.
For example:
The web service response with a list of:
<charge>
<type>ABC</type>
<qualifier>3</qualifier>
<periodCode>004</periodCode>
<code>STE</code>
</charge>
<charge> ... </charge>
Which will be encapsulated in a class like this:
class Charge {
string type { get; set; }
string qualifier { get; set; }
string periodCode { get; set; }
string code { get; set; }
decimal rate { get; set; }
}
Our model is:
public class RCharge {
public string Description { get; set; }
public bool? IncludedInRate { get; set; }
public decimal? AmountValue { get; set; }
public string Period { get; set; }
}
I have stored in a database the information related to the codes and descriptions, as all codes have their own description.
The problem is how to map from the code returned in the web service, to the description. I have this code, and I could make a call to the database in search of the code and get the description, but is it ok? I guess the ConstructUsing is executed for every item in the response, so make a query here would result in a bunch of requests to DB.
AutoMapper.Mapper.Initialize(config => {
config
.CreateMap<Charge, RCharge>()
.ConstructUsing(s => RChargeConstructor.Construct(s));
});
public class RChargeConstructor {
public static RCharge Construct(ResolutionContext context) {
if (context == null || context.IsSourceValueNull)
return null;
var src = (Charge)context.SourceValue;
return new RCharge() {
Description = src.type, // want description from DB
IncludedInRate = src.qualifier == "3",
AmountValue = src.rate,
Period = src.periodCode // want description from DB
};
}
}
Is there a good approach for doing this kind of mapping?
I have a similar structure to the one below
Base class
public class BaseClass
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public Guid Guid { get; set; }
public string Hometown { get; set; }
}
Derived Class
public class DerivedClass : BaseClass
{
public List<DerivedClassDataItem> Data { get; set; }
}
Data class
public class DerivedClassDataItem
{
public string Datum1 { get; set; }
public string Datum2 { get; set; }
public string Datum3 { get; set; }
public string Datum4 { get; set; }
public int Datum5 { get; set; }
public DateTime Datum6 { get; set; }
}
What is the best practice to return specific set of info from the DerivedClass?
a potential set could be:
Name, Address, Guid and then a Data list that only contains Datum1 and Datum4
I could see anonymousTypes, Tuples or another set of class(es), all to be valid approaches.
My concern about creating new set of classs for the set returned is that the class(s) structure will be similar to the structure of the three mentioned above except it will have fewer selected members, which to me, does not sound ideal. (duplicate code and structure)
Using anonymousTypes was my initial solution to tackle this, something like
List<DerivedClass> list = new List<DerivedClass>();
var mySet = list.Select(d => new
{
Name = d.Name,
Address = d.Address,
.
.
.
.
.
Data = d.Data.Select(item => new
{
Datum1 = item.Datum1,
Datum4 = item.Datum4
})
});
but again, that was a headache for us to track through httpResponse and through out API calls.
Should I go with Tuple?
Any insights as to what is the best practice for doing this?
Edit
I am using this set of data to be a response returned by a API/GET call. I will send the set back using HttpRespose and then the framework will transform that into json
this is an actual method we have now
private void populateReturnFile()
{
var returnFileAnonymous = new
{
Vendor = this.Vendor,
OrganizationName = this.OrganizationName,
User = this.User,
Platform = this.Platform,
DictionaryType = this.DictionaryType,
UseCaseId = this.UseCaseId,
Data = this.Data.Select(d => new
{
MigrationTermId = d.MigrationTermId,
ImoLexicalCode = d.ImoLexicalCode
})
};
this.returnFile = returnFileAnonymous;
}
Then my GET will return the retunFile (this is a very simple method, i have remove irrelevant code)
[HttpGet]
public HttpResponseMessage Get(Guid migrationFileId)
{
ProblemList problemList = ProblemList.GetProblemList(migrationFileId);
return Request.CreateResponse(HttpStatusCode.OK, problemList.ReturnFile, new JsonMediaTypeFormatter());
}
If API calls is where you are using these classes, then I personally like to keep it simple and avoid complex inheritance hierarchy. Remember, simple code is good code.
I would make a separate class for each api request/response call. For very simple api calls (ajax requests for example) I like to use anonymous types, but for controllers that only handle API calls I like to create separate classes, organized in a nice folder structure.
Everyone has their "style" but as long as you strive for simplicity your code will be maintainable.
I am using mashape api for getting the speed post tracking information:-
https://www.mashape.com/blaazetech/indian-post
As this is in .NET c# following code is not getting complied:-
Task<HttpResponse<MyClass>> response = Unirest.get("https://indianpost.p.mashape.com/index.php?itemno=EF990403084IN")
.header("X-Mashape-Key", mykey)
.header("Accept", "application/json")
.asJson();
the complie error is "The type arguments for method 'unirest_net.request.HttpRequest.asJson()' cannot be inferred from the usage. Try specifying the type arguments explicitly."
I am not sure how this api can be consumed. Is it problem with "MyClass" and what?
RSDC - Ok, turns out that your API endpoints for Indian-Post don't work anyways. Tested them on Mashape and it returns error.
>>> I got it working for the metaCritic GET API <<<
https://www.mashape.com/byroredux/metacritic (Game List API, 2nd one down)
re: MyClass
1) On the mashape.com site in the API documentation page, find the 200/JSON response on the right side.
2) Copy the json data
3) go to http://json2csharp.com/ and paste the code
4) click Generate button to get c# class code. Copy the class code.
5) back in VS, go to Models folder and create class called MyClass.cs.
6) paste your code in as such:
public class MyClass
{
public class Result
{
public string name { get; set; }
public string score { get; set; }
public string url { get; set; }
public string rlsdate { get; set; }
public string rating { get; set; }
public string summary { get; set; }
public string platform { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}
}
7) Try this:
HttpResponse<MyClass.RootObject> response = Unirest.get("https://byroredux-metacritic.p.mashape.com/game-list/ps4/coming-soon")
.header("X-Mashape-Key", "KxdVFN6Vlymshd5ezOQwBvS2Svjtp1bq5YOjsnFOkgTOwqwM6y")
.header("Accept", "application/json")
.asJson<MyClass.RootObject>();
If you run the debugger, you can see that response > Body > results now holds 25 items of data.