Return list web method - c#

I have Web service and a method which makes a request to my table 'Customer' with Entity Framework.
I want to return the result of my request :
public List<Customer> MyMethod(int id)
{
Model model = new Model();
List<Customer> customer = new List<Customer>();
try
{
customer = model.Customer.Where(x => x.Id == id).ToList();
}
catch(Exception ex)
{
throw new System.NullReferenceException();
}
return customer;
}
In debug mode I have a list filled but when I call the method via SoapUI I have no answer.
Thank you

My full code :
Class Customer (generated by EF) :
[Table("Customer")]
public partial class Customer
{
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
public int? Adress_id { get; set; }
public virtual Adress Adress { get; set; }
}
Class Adress (generated by EF) :
[Table("Adress")]
public partial class Adress
{
public Adress()
{
Customer = new HashSet<Customer>();
}
public int Id { get; set; }
[Column("Adress")]
[StringLength(255)]
public string Adress1 { get; set; }
[StringLength(50)]
public string Town { get; set; }
public virtual ICollection<Customer> Customer{ get; set; }
}
My Web Method :
[WebMethod]
public Customer MyMethod(int id)
{
Model model = new Model();
Customer customer = new Customer();
try
{
customer = model.Customer.Where(x => x.Name == id).First();
}
catch (Exception ex)
{
throw new System.NullReferenceException(ex.Message, ex.InnerException);
}
return customer;
}

please refer to the following code:
public List<UserInfo> GetAllUserInfoDetailes()
{
List<UserInfo> user = new List<UserInfo>();
using (Model1 pubs = new Model1())
{
var userId = (from p in pubs.TB_UserInfo select p);
foreach (TB_UserInfo singleUser in userId)
{
UserInfo a = new UserInfo();
a.EUserId = singleUser.User_Id;
a.EUser_Name = singleUser.User_Name;
a.EAlias = singleUser.Alias;
a.EPassword = singleUser.Password;
a.EState = singleUser.State;
a.ECurrentPrevious = singleUser.CurrentPrevious;
a.EEmail = singleUser.Email;
a.EReportDutyTime = singleUser.ReportdutyTime;
a.ETeam_Id = singleUser.Team_Id;
a.ELogin_Time = DateTime.Now;
user.Add(a);
}
}
return user;
}
Then it can get the result.

I have a virtual property in my class Customer which corresponds to another table (foreign key). If I remove this virtual property, I have a reponse but I want to return the joint

Add WebMethod attribute to your method:
[WebMethod]
public List<Customer> MyMethod(int id)
{....}

Related

How to return correct values for listview using WCF?

I want to populate listview with information retrieved from database using WCF in C# and am not able to retrieve correct data for listview binding.
public interface IServicePl
{
[OperationContract]
[OperationContract]
IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments();
}
[DataContract]
public class InterventiiCuEchipament
{
[DataMember]
public string EchipamentInterventie { get; set; }
public int id_interventie { get; set; }
public string tip_interventie { get; set; }
public string responsabil { get; set; }
public DateTime data_finalizare { get; set; }
public bool status { get; set; }
}
public IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments()
{
try
{
IEnumerable<InterventiiCuEchipament> query = from sel1 in dataP.interventiis
join sel2 in dataP.sesizaris
on sel1.id_interventie equals sel2.id_sesizare
select new InterventiiCuEchipament()
{
id_interventie = sel1.id_interventie,
EchipamentInterventie = sel2.echipament,
tip_interventie = sel2.tip_sesizare,
responsabil = sel1.responsabil,
data_finalizare = (DateTime)sel1.data_finalizare,
status = (bool)sel1.status
};
return query;
}
On the client side I have the following code :
if (client.InnerChannel.State != CommunicationState.Faulted)
{
List<InterventiiCuEchipament> ListaInterventii = new List<InterventiiCuEchipament>();
ListaInterventii = client.GetInterventiiCuEchipamentsAsync().Result.ToList();
InterventiiList.ItemsSource = ListaInterventii;
InterventiiList.Items.Refresh();
}
Output from query is ok, like in this image
Output for listview binding is like in this image
Why I can see just the count of query? and not correct values returned by query.
If the query returns values, then ListaInterventii should also have values.
I wrote a similar demo, you can compare it.
You can use foreach to see if there is a value.
ListaInterventii = client.GetInterventiiCuEchipamentsAsync().Result.ToList();
foreach(var a in ListaInterventii)
{
int A = a.id_interventie;
}
Demo
public class ProductService : IServicePl
{
public IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments()
{
// This comes from database.
var _dbCountries = new List<InterventiiCuEchipament>
{
new InterventiiCuEchipament {id_interventie = 1, tip_interventie="1"},
new InterventiiCuEchipament {id_interventie = 2, tip_interventie="2"},
new InterventiiCuEchipament {id_interventie = 3, tip_interventie="3"},
};
return _dbCountries;
}
}
[ServiceContract]
public interface IServicePl
{
[OperationContract]
IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments();
}
[DataContract]
public class InterventiiCuEchipament
{
[DataMember]
[Key]
public int id_interventie { get; set; }
public string tip_interventie { get; set; }
}
client side
ServicePlClient client = new ServicePlClient();
List<InterventiiCuEchipament> ListaInterventii = new List<InterventiiCuEchipament>();
ListaInterventii = client.GetInterventiiCuEchipamentsAsync().Result.ToList();

ASP.NET C# OData Service + Navigation Property + $expand = null. What am I missing?

I will try to explain my problem as thoroughly as possible with a simplified example. Please note that I am NOT using Entity Framework.
I have this model:
public class Person
{
[Key]
public Guid Id { get; set; }
public string GivenName { get; set; }
public string FamilyName { get; set; }
public List<Employment> Employments { get; set; }
}
public class Employment
{
public string Role { get; set; }
public Guid? ManagerId { get; set; }
public virtual Person Manager { get; set; }
}
I create an in-memory data source:
public class MyDataSource
{
private static MyDataSource instance = null;
public static MyDataSource Instance
{
get
{
if (instance == null)
{
instance = new MyDataSource();
}
return instance;
}
}
public List<Person> Persons { get; set; }
private MyDataSource()
{
this.Persons = new List<Person>();
this.Persons.AddRange(new List<Person>
{
new Person()
{
Id = Guid.Parse("00000000-0000-0000-0000-000000000001"), //Just for simplicity
GivenName = "John",
FamilyName = "Doe",
Employments = new List<Employment>()
{
new Employment()
{
Role = "Boss"
}
}
},
new Person()
{
Id = Guid.Parse("00000000-0000-0000-0000-000000000002"), //Just for simplicity
GivenName = "Clark",
FamilyName = "Kent",
Employments = new List<Employment>()
{
new Employment()
{
Role = "Worker",
ManagerId = Guid.Parse("00000000-0000-0000-0000-000000000001"), //Just for simplicity
}
}
}
});
}
}
I have this controller:
[EnableQuery]
public class PersonsController : ODataController
{
public IHttpActionResult Get()
{
return Ok(MyDataSource.Instance.Persons)
}
}
I configure the EndPoint:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapODataServiceRoute("ODataRoute", "odata", CreateEdmModel());
config.Select().Expand().Filter().OrderBy().MaxTop(null).Count()
}
public static IEdmModel CreateEdmModel()
{
var builder = new ODataConventionModelBuilder();
var persons = builder.EntitySet<Person>("Persons");
builder.ComplexType<Employment>().HasOptional(e => e.Manager, (e, p) => e.ManagerId == p.Id);
return builder.GetEdmModel();
}
}
Checking the $metadata I see this:
<NavigationProperty Name="Manager" Type = "MyNamespace.Person">
<ReferentialConstraint Property="ManagerId" ReferenceProperty="Id" />
</NavigationProperty
Everything looks fine from what I can tell but:
https://example.com/odata/persons?$expand=Employments/Manager
receives everything fine but:
Manager is null for both persons. I was expecting to see John Doe on Clark Kents employment.
What am I missing?
I have solved it myself.
I realised that it doesn't work like I thought and that I have to add a reference to the manager directly in MyDataSource. After that it works to $expand the manager.

includeDetails not working in ABP Framework

I have a simple project (ABP version: 3.1.2, Database: EF Core).
I run GetAsync:
var author = await _authorRepository.GetAsync(id, includeDetails: true);
But author.Films was not included. What may I have forgotten?
Author (AggregateRoot):
public class Author : FullAuditedAggregateRoot<Guid>
{
public string Name { get; private set; }
public DateTime BirthDate { get; set; }
public string ShortBio { get; set; }
public List<Film> Films { get; set; }
private Author()
{
Films = new List<Film>();
/* This constructor is for deserialization / ORM purpose */
}
internal Author(
Guid id,
[NotNull] string name,
DateTime birthDate,
[CanBeNull] string shortBio = null)
: base(id)
{
Name = name;
BirthDate = birthDate;
ShortBio = shortBio;
Films = new List<Film>();
}
}
Film (Entity):
public class Film : Entity<Guid>
{
public virtual Guid AuthorId { get; internal set; }
public string Name { get; set; }
}
SeedAsync in DataSeeder class (I checked whether data exists in database after DbMigrator ran, there are these data in tables as expected):
public async Task SeedAsync(DataSeedContext context)
{
if (await _authorRepository.GetCountAsync() == 0)
{
var authorId = _guidGenerator.Create();
await _authorRepository.InsertAsync(
new Author(authorId, "J. R. R. Tolkien", DateTime.Now.AddYears(-60), "bio1"),
autoSave: true
);
await _filmRepository.InsertAsync(
new Film { AuthorId = authorId, Name = "The Return of the King1" },
autoSave: true);
await _filmRepository.InsertAsync(
new Film { AuthorId = authorId, Name = "The Return of the King2" },
autoSave: true);
await _filmRepository.InsertAsync(
new Film { AuthorId = authorId, Name = "The Return of the King3" },
autoSave: true);
}
}
AuthorAppService:
public class AuthorAppService : BookStoreAppService, IAuthorAppService
{
private readonly IAuthorRepository _authorRepository;
private readonly AuthorManager _authorManager;
public AuthorAppService(
IAuthorRepository authorRepository,
AuthorManager authorManager)
{
_authorRepository = authorRepository;
_authorManager = authorManager;
}
public async Task<AuthorDto> GetAsync(Guid id)
{
var author = await _authorRepository.GetAsync(id, includeDetails: true);
return ObjectMapper.Map<Author, AuthorDto>(author);
}
}
From https://docs.abp.io/en/abp/latest/Best-Practices/Entity-Framework-Core-Integration:
Do create a IncludeDetails extension method for the IQueryable<TEntity> for each aggregate root which has sub collections.
...
Do override WithDetails method of the repository for aggregates root which have sub collections.
public static class AuthorEfCoreQueryableExtensions
{
public static IQueryable<Author> IncludeDetails(this IQueryable<Author> queryable, bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(x => x.Films);
}
}
public class AuthorRepository : EfCoreRepository<IMyDbContext, Author, Guid>, IAuthorRepository
{
...
public override IQueryable<Author> WithDetails()
{
return GetQueryable().IncludeDetails(); // Uses the extension method defined above
}
}

Posting data to sql server using servicestack and c#

I'm just starting to learn servicestack and c# and I need some help with posting data to sql server. When I test using swagger I get a 200 response but nothing is actually being inserted into the database and I'm not sure where I'm going wrong.
Model.Type
public class Book
{
[PrimaryKey]
[AutoIncrement]
public int BookID { get; set; }
public string Author { get; set; }
public string Title { get; set; }
public int NumberOfPages { get; set; }
public int Isbn { get; set; }
}
Manager Interface:
namespace ServiceStackServiceLog4NetTemplate.Interfaces.Managers
{
public interface IPostBookManager
{
Book CreateBooks();
}
}
Repository Interface:
namespace ServiceStackServiceLog4NetTemplate.Interfaces.Repositories
{
public interface IPostBookRepository
{
Book PostBooks();
}
}
Messages.Request
namespace ServiceStackServiceLog4NetTemplate.ServiceModel.Messages
{
[Route("/PostBooks", Verbs = "POST")]
public class PostBooksRequest
{
[AutoIncrement]
public int BookID { get; set; }
public string Author { get; set; }
public string Title { get; set; }
public int NumberOfPages { get; set; }
public int Isbn { get; set; }
}
}
Messages.Response
namespace ServiceStackServiceLog4NetTemplate.ServiceModel.Messages
{
public class PostBooksResponse : IHasResponseStatus
{
public Book Book { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
}
Manager
class PostBooksManager : IPostBookManager
{
private IPostBookRepository postRepo;
public PostBooksManager(IPostBookRepository pRepo)
{
postRepo = pRepo;
}
public Book CreateBooks()
{
var bookCreations = postRepo.PostBooks();
return bookCreations;
}
}
}
Repository
namespace ServiceStackServiceLog4NetTemplate.Repositories
{
public class PostBookSqlRepo : IPostBookRepository
{
private readonly string connection = ConfigurationManager.AppSettings["BooksDB"];
public Book PostBooks()
{
var postBooks = CreateBooks();
return postBooks;
}
private Book CreateBooks()
{
var newBooks = new Book();
string query = "INSERT INTO dbo.BooksTable(BookID, Author, Title, NumberOfPages, ISBN)" +
"VALUES(#BookID, #Author, #Title, #NumberOfPages, #ISBN)";
SqlConnection dbConnect = new SqlConnection(connection);
SqlCommand cmd = new SqlCommand(query, dbConnect);
using (dbConnect)
{
dbConnect.Open();
var b = new Book()
{
BookID = newBooks.BookID,
Author = newBooks.Author,
Title = newBooks.Title,
NumberOfPages = newBooks.NumberOfPages,
Isbn = newBooks.Isbn
};
cmd.Parameters.AddWithValue("#BookID", b.BookID);
cmd.Parameters.AddWithValue("#Author", b.Author);
cmd.Parameters.AddWithValue("#Title", b.Title);
cmd.Parameters.AddWithValue("#NumberOfPages", b.NumberOfPages);
cmd.Parameters.AddWithValue("#ISBN", b.Isbn);
dbConnect.Close();
}
return newBooks;
}
}
}
Service Definition
namespace ServiceStackServiceLog4NetTemplate.ServiceDefinition
{
[EnableCors(allowedMethods: "GET,POST,DELETE")]
class PostBooksServiceDefinition : Service
{
private IPostBookManager postManager;
public PostBooksServiceDefinition(IPostBookManager bookP)
{
postManager = bookP;
}
public object Post(PostBooksRequest request)
{
var postBook = request.ConvertTo<Book>();
PostBooksResponse resp = new PostBooksResponse()
{
Book = postBook
};
return resp;
}
}
}
First you shouldn't have [AutoIncrement] on your Request DTO, you're converting the DTO to a Book object which is the data model you're saving, not the Request DTO. (It doesn't have any impact on anything, it's just unnecessary and unused).
Secondly, you're using OrmLite Data Attributes in your Book data model but you're not using OrmLite to insert the record.
To use OrmLite to insert a new Book in your ServiceStack Services you can just use:
Db.Insert(postBook);
If you also need to create the Book RDBMS table, you can create it if it doesn't already exist with:
using (var db = dbFactory.Open())
{
db.CreateTableIfNotExists<Book>();
}
If you haven't registered your OrmLiteConnectionFactory with ServiceStack, you can register it with:
container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(connString, SqlServer2012Dialect.Provider));
See the docs on OrmLite project page for more info:
https://github.com/ServiceStack/ServiceStack.OrmLite
Using a Repository
If you want to use PostBookSqlRepo to save your books you should configure it with your IDbConnectionFactory, e.g:
public class PostBookSqlRepo : IPostBookRepository
{
IDbConnectionFactory dbFactory;
public PostBookSqlRepo(IDbConnectionFactory dbFactory)
{
this.dbFactory = dbFactory;
}
//...
public Book CreateBooks(Book book)
{
using (var db = dbFactory.OpenDbConnection())
{
db.Insert(book);
}
}
}
Which you can configure in your ServiceStack IOC with:
container.Register<IPostBookRepository>(c =>
new PostBookSqlRepo(c.Resolve<IDbConnectionFactory>()));

Dependent Object Creation

Environment:
I am working in Webapi. There is 2 entity classes which are follows;
public class Class1
{
public Class1()
{
this.items = new HashSet<Class2>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Class2> items { get; set; }
}
public class Class2
{
public int Id { get; set; }
public string Name { get; set; }
public int Class1Id { get; set; }
public virtual Class1 class1 { get; set; }
}
Business Layer:
The buniess layer have the following codes;
public class Class1Logic : IClass1Logic
{
private readonly IClass1Repository _repo;
public Class1Logic(IClass1Repository repository)
{
_repo = repository;
}
public async Task<bool> AddClass1ItemAsync(Class1 item)
{
_repo.Add(item);
bool status = await _repo.SaveAsync();
return status;
}
public async Task<Class1> GetClass1ItemAsync(int id)
{
return await _repo.GetAsync(id);
}
}
public class Class2Logic : IClass1Logic
{
private readonly IClass2Repository _repo;
public Class2Logic(IClass2Repository repository)
{
_repo = repository;
}
public async Task<bool> AddClass2ItemAsync(Class2 item)
{
_repo.Add(item);
bool status = await _repo.SaveAsync();
return status;
}
public async Task<Class2> GetClass2ItemAsync(int id)
{
return await _repo.GetAsync(id);
}
}
ViewModels:
public class Class1Model
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Class2Model
{
public int Id { get; internal set; }
public string Name { get; set; }
public int Class1Id { get; set; }
public string Class1Name { get; internal set; }
}
Controllers:
There are 2 contrtollers like Class1Controller and Class2Controller. Both have all CRUD operations.
[RoutePrefix("api/class1items")]
public class Class1Controller : ApiController
{
private readonly IClass1Logic _class1Logic;
private ModelFactory TheFactory;
public Class1Controller(IClass1Logic class1Logic)
{
_class1Logic = class1Logic;
TheFactory = new ModelFactory();
}
[Route("")]
public async Task<IHttpActionResult> Post(Class1Model class1Model)
{
var item = TheFactory.Parse(class1Model);
bool result = await _class1Logic.AddClassItemAsync(item);
if (!result)
{
return BadRequest("Error");
}
string uri = Url.Link("GetLabById", new { id = item.Id });
return Created(uri, TheFactory.Create(item));
}
[Route("{id:int}", Name = "GetClass1ItemById")]
public async Task<IHttpActionResult> GetClass1Item(int id)
{
Class1 item = await _class1Logic.GetClassItemAsync(id);
if (item == null)
{
return NotFound();
}
return Ok(TheFactory.Create(item));
}
}
[RoutePrefix("api/class2items")]
public class Class2Controller : ApiController
{
private readonly IClass2Logic _class2Logic;
private ModelFactory TheFactory;
public Class2Controller(IClass2Logic class2Logic)
{
_class2Logic = class2Logic;
TheFactory = new ModelFactory();
}
[Route("")]
public async Task<IHttpActionResult> Post(Class2Model class2Model)
{
var item = TheFactory.Parse(class2Model);
***//Here item should include Class1 object even if user give ClassId in class2Model***
bool result = await _class2Logic.AddClassItemAsync(item);
if (!result)
{
return BadRequest("Error");
}
string uri = Url.Link("GetClass2ItemById", new { id = item.Id });
return Created(uri, TheFactory.Create(item));
}
}
There is not dependecies in Class1. So all operations are fine. In Class2Controller post method, I got the model object as following to create Class2.
{
"id": 0,
"name": "string",
"class1Id": 1
}
Understanding:
I need to return this viewmodel to user after the create the record. The record created successfully but when mapping to viewmodel i got null exception as Class1 object not in the Class2 object.
In order to get the Class2 object including class1 object, I need to give the class1Object in the request object.
For this i need to find the Class1 object with Class1Id in the request object.
ViewMapper Code:
public class ModelFactory
{
public Class1Model Create(Class1 item)
{
return new Class1Model
{
Id = item.Id,
Name = item.Name
};
}
public Class2Model Create(Class2 item)
{
return new Class2Model
{
Id = item.Id,
Name = item.Name,
Class1Id = item.class1.Id,
Class1Name = item.class1.Name
};
}
public Class1 Parse(Class1Model modelItem)
{
return new Class1
{
Id = modelItem.Id,
Name = modelItem.Name
};
}
public Class2 Parse(Class2Model modelItem)
{
return new Class2
{
Id = modelItem.Id,
Name = modelItem.Name,
Class1Id = modelItem.Class1Id,
***/*Issue Place*/
//class1 = Need to set property by getting object using modelItem.Class1Id***
};
}
}
Issue:
Now i need to call get method of Class1Controller by passing Class1Id.
How to call and is this correct? or my design is bad?
This is initial case. If my Class3 have both Class1 and Class2 again i need to call methods of Class1 and Class2.
Please help to find the correct solution in this case
Note: I added comments the issue area to understand
Well, just to fix this issue you need to manually call _class1Logic.GetClass1ItemAsync after saving. However this doesn't look good.
More elegant ways to fix it:
1) If you always need Class2.Class1 field to be filled use Include when you fetch data (in repository): dbContext.Set<Class2>().Include(c => c.class1).
2) Also you can turn on LazyLoading for EF - I assume it should work in your case.
3) Inject class1Repo to class2Logic and fix up class1 reference after saving - in case if you don't want to enable lazy loading or item was detached from context after save method
Thoughts about design:
I suggest you to look at Automapper or simular libraries instead of ModelFactory where you going to have all mapping logic
Edit: About generic repository: you can modify you GetAsync method
public async Task<T> GetAsync<T>(int id, params Expression<Func<T, object>>[] includes)
where T: class, IEntity
{
var query = context.Set<T>().AsQueryable();
if (includes.Length > 0)
{
query = includes.Aggregate(query,
(current, include) => current.Include(include));
}
return await query.FirstOrDefaultAsync(x => x.Id == id);
}
IEntity interface:
interface IEntity
{
int Id { get; }
}
With this implementation you can use
await _repo.GetAsync<Class2>(id, x => x.class1);

Categories