AppEngine + Datastore + Objectify: Http Request returns inconsistent responses - google-app-engine

I am implementing AppEngine server as a backend for my Android application. I use Datastore, I query it via Objectify service and I use Endpoints that I call via URL.
I have an entity User with properties like this:
#Id
Long id;
/**
* Name or nickname of the user
*/
public String name;
#Index
public String email;
#JsonIgnore
List<Key<User>> friends;
public User()
{
devices = new ArrayList<String>();
friendsWithKey = new ArrayList<Key<User>>();
}
public static User findRecordById(Long id)
{
return ofy().load().type(User.class).id(id).now();
}
#ApiMethod(name = "friends", httpMethod = "GET", path = "users/{userId}/friends")
public JSONObject getFriends(#Named("userId") String userId)
{
User user = User.findRecordById(Long.parseLong(userId));
JSONObject friendsObject = new JSONObject();
JSONArray jsonArray = new JSONArray();
JSONObject friend;
List<User> userList = new ArrayList<User>();
if (user.friendsWithKey != null)
{
for (Key<User> id : user.friendsWithKey)
{
friend = new JSONObject();
User user1 = User.findRecordById(id.getId());
userList.add(user1);
friend.put("name", user1.name);
friend.put("email", user1.email);
friend.put("id", user1.id);user1.lastTimeOnline.getTime());
jsonArray.add(friend);
}
friendsObject.put("friends", jsonArray);
}
return friendsObject;
}
It sometimes returns only a subset of friends. It is weird and I do not get where I could go wrong. If I get the User object from the DB, it already has a wrong List of Key values. But if I look into the database via console, I can see all of the users that ahve been added as friends.
I reaally need to fix this bug. Please, help.
It is very strange because it only happens once in a while and is non-deterministic in every way.

Related

It is necessary to perform the planned action through the apex scheduler

i have this code:
public static String currencyConverter() {
allCurrency test = new allCurrency();
HttpRequest request = new HttpRequest();
HttpResponse response = new HttpResponse();
Http http = new Http();
request.setEndpoint(endPoint);
request.setMethod('GET');
response = http.send(request);
String JSONresponse = response.getBody();
currencyJSON currencyJSON = (currencyJSON)JSON.deserialize(JSONresponse, currencyJSON.class);
test.USD = currencyJSON.rates.USD;
test.CAD = currencyJSON.rates.CAD;
test.EUR = currencyJSON.rates.EUR;
test.GBP = currencyJSON.rates.GBP;
Log__c logObject = new Log__c();
logObject.Status_Code__c = String.valueOf(response.getStatusCode());
logObject.Response_Body__c = response.getBody();
insert logObject;
if (response.getStatusCode() == 200) {
Exchange_Rate__c ExchangeRateObject = new Exchange_Rate__c();
ExchangeRateObject.CAD__c = currencyJSON.rates.CAD;
ExchangeRateObject.EUR__c = currencyJSON.rates.EUR;
ExchangeRateObject.GBP__c = currencyJSON.rates.GBP;
ExchangeRateObject.USD__c = currencyJSON.rates.USD;
ExchangeRateObject.Log__c = logObject.id;
insert ExchangeRateObject;
}
return JSON.serialize(test);
}
Here I am getting different currencies and then calling them in LWC and also I create two objects with values.
I want these objects to be created every day at 12PM.
Tell me how to implement this through the apex scheduler.
You need a class that implements Schedulable. Can be this class, just add that to the header and add execute method. Or can be separate class, doesn't matter much.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm
Something like
public with sharing MyClass implements Schedulable{
public static String currencyConverter() { ... your method here }
public void execute(SchedulableContext sc) {
currencyConverter();
}
}
Once your class saves OK you should be able to schedule it from UI (Setup -> Apex Classes -> button) or with System.schedule 1-liner from Developer Console for example.
Alternative would be to have a scheduled Flow - but that's bit more work with making your Apex callable from Flow.
P.S. Don't name your variables test. Eventually some time later you may need "real" stuff like Test.isRunningTest() and that will be "fun". It's like writing
Integer Account = 5; // happy debugging suckers

WCF Service and Windows Application Client. why client receives null

I have mapped the service with a linq to Sql classes and I am using wcf library for vs 2019 and in client a win form app.
I am trying sending the class created for linq to sql the next way
public List<Trades> GetAllTradings()
{
context = new DCStockTradingDataContext();
List<Trades> tradings = (from t in context.Trades
select t).ToList();
return tradings;
}
and the client
private void btnRun_Click(object sender, EventArgs e)
{
Service1Client client = new Service1Client();
var trades = client.GetAllTradings();
dgViewStocks.DataSource = trades;
//string ret = client.GetData("Hello");
//Console.WriteLine(ret);
}
I din´t know what is happening and I don´t know what is wrong
The service
and the client receives all null
I would appreciate any help about this and thank you in advance
If you get null response in WCF client, some advices:
try to call the service in SoapUi with Validation of request and response turned on. It may be useful in detecting problems.
debug Reference.cs file to see more closely what is going on
use MessageInspector to see what is received in AfterReceiveReply method
examine namespaces attentively, response often cannot be deserialized because of the difference in namespaces that are in Reference.cs and in real service
Thanks for your response and everything if this I did.
I found how I have to work with linq to sql classes and wcf. We need to take into account that you need to convert the List of linq classes to List<string. What I did
enter code here
public List<string[]> GetAllStocks()
{
context = new DCStockTradingDataContext();
System.Data.Linq.Table<Stocks> stocks = context.GetTable<Stocks>();
var allStock = (from st in stocks
select new
{
stockId = (string) st.CodeID,
currency = (char) st.Currency,
stName = st.Name,
price = (decimal) st.Price,
volument = (decimal) st.Volumen
}).ToList();
List<string[]> listRetruned = new List<string[]>();
foreach (var tr in allStock)
{
string[] t = new string[5];
t[0] = tr.stockId;
t[1] = tr.currency.ToString();
t[2] = tr.stName;
t[3] = tr.price.ToString();
t[4] = tr.volument.ToString();
listRetruned.Add(t);
}
return listRetruned;
}
and the client
I have created a model class with the expected data
public class TradingModel
{
public string TradeID { get; set; }
public string StockId { get; set; }
public decimal Bid { get; set; }
public int BidQty { get; set; }
public decimal Ask{get;set;}
public int AskQty { get; set; }
public decimal Last { get; set; }
}
and finally the method
List<TradingModel> models = new List<TradingModel>();
for(int i = 0; i < trades.Length; i++)
{
TradingModel model = new TradingModel()
{
Ask = Convert.ToDecimal(trades[i][0]),
Bid = Convert.ToDecimal(trades[i][1]),
BidQty = Convert.ToInt32(trades[i][2]),
AskQty = Convert.ToInt32(trades[i][3]),
Last = Convert.ToDecimal(trades[i][4]),
StockId = trades[i][5],
TradeID = trades[i][6],
};
models.Add(model);
}
dgViewStocks.DataSource = models;
I am not sure if this is the best way to jump to next step, but it worked for me. If someone is looking for this info as I did, wasting several days chasing the solution, I leave what I did.
There is off course changing the service and generate the proxy again

How to store data owned by User?

I'm learning Google App Engine + Google Cloud Endpoints + Objectify and I'm trying to understand how to create REST API which will let each particular user to save his data in the cloud.
My current struggle is how to store Entity owned by the User (com.google.appengine.api.users.User)?
So far I have endpoint:
#ApiMethod(name = "saveBook")
public void saveBook(Book book, User user) throws OAuthRequestException, IOException {
if (user == null) {
throw new OAuthRequestException("User is not authorized");
}
ofy().save()
.entity(BookRecord.fromBook(user, book))
.now();
}
Entity (in this context let's assume that User wrote the book):
#Entity
public class BookRecord {
#Parent
private Key<User> user;
#Id
private String id;
#Index
private String name;
public static BookRecord fromBook(User user, Book book) {
return new BookRecord(
Key.create(user),
book.getId(),
book.getName()
);
}
public BookRecord() {
}
private BookRecord(Key<User> user, String id, String name, String author) {
this.user = user;
this.id = id;
this.name = name;
this.author = author;
}
}
Problem arises from User not being an Entity, so I can't really use this solution and use User as #Parent directly. What is the general solution to solve this problem and store data owned by User?
Create your own User entity, this is where you'll store custom information/preferences for your app (as I suggested here).
You'll be using getUserId() to tie it with the Google user, and from there on you're free to use it as needed.

[RuntimeException: No EntityManager bound to this thread. Try to annotate your action method with #play.db.jpa.Transactional]

this is the problem once i try to save data into db with sql statement insert.
my function is this:
public void save(){
JPA.em().persist(this);
}
and
public static Result registered() {
Form<User> requestform = form(User.class).bindFromRequest();
if(requestform.hasErrors()){
return badRequest("<p>fehlerhafte eingabe!</p>").as("text/html");
} else {
User user = requestform.get();
String fullname = user.fullname;
String email = user.email;
String password = user.password;
String username = user.username;
new User(username, password, fullname, email).save();
}
return redirect(controllers.routes.Application.index());
}
thanks for help
It is just like the debugging message says, you do not have an entity manager bound to your methods because they are not marked as transactions.
#play.db.jpa.Transactional
public static Result registered() {
Also, if you are using EBean, you could just extend Model for your User class, which comes with many handy built in functions for database use, see documentation here: http://www.playframework.org/documentation/2.0.1/JavaEbean

How to Use a Web Service to Update TextBox controls in ASP.NET?

I have a web form where I need to add, update, delete and read using a unique ID. So far I have managed to add, update and delete functions with little trouble.
However now I am having trouble getting my read function to work (understand I have a webform that has four text fields; ID, FIRSTNAME, SURNAME AND ADDRESS). Basically when an ID that has been previously created (using add button) is entered into the text field and the read button clicked it should update the other 3 text fields with the stored entries depending on the ID entered.
Here is my behind code (cs.) on the web form
protected void cmdRead_Click(object sender, EventArgs e)
{
// Create a reference to the Web service
DbWebService.WebService1 proxy = new DbWebService.WebService1();
// Create a person details object to send to the Web service.
string ADDRESS;
string SURNAME;
string FIRSTNAME;
string ID;
ADDRESS = txtAddress.Text;
SURNAME = txtSurname.Text;
FIRSTNAME = txtFirstname.Text;
ID = txtID.Text;
// Attempt to store in the Web service
bool rsp = proxy.ReadPerson(int.Parse(ID), FIRSTNAME, SURNAME, ADDRESS);
// Inform the user
if (rsp)
{
lblOutcome.Text = "Successfully read data.";
txtFirstname.Text = FIRSTNAME;
txtSurname.Text = SURNAME;
txtAddress.Text = ADDRESS;
}
else
{
lblOutcome.Text = "Failed to read data! Select a previously created ID!";
}
}
and here is my web function on the web service (which is where the SQL Server Express database is)
[WebMethod]
public bool ReadPerson(int ID, string FIRSTNAME, string SURNAME, string ADDRESS)
{
// In case of failure failure first
bool rtn = false;
// Connect to the Database
SqlConnection connection = new SqlConnection(#"Data Source=.\SQLEXPRESS;AttachDbFilename='|DataDirectory|\Database.mdf';Integrated Security=True;User Instance=True");
// Open the connection
connection.Open();
// Prepare an SQL Command
SqlCommand command = new SqlCommand(String.Format("SELECT FIRSTNAME, SURNAME, ADDRESS FROM PersonalDetails WHERE ID = '{0}'", ID), connection);
// Execute the SQL command and get a data reader.
SqlDataReader reader = command.ExecuteReader();
// Instruct the reader to read the first record.
if (reader.Read())
{
// A record exists, thus the return value is updated
FIRSTNAME = (string)reader["FIRSTNAME"];
SURNAME = (string)reader["SURNAME"];
ADDRESS = (string)reader["ADDRESS"];
rtn = true;
}
// Close the connection
connection.Close();
// Return the result.
return (rtn);
}
Now the problem is when I click read I get a success message (using a label as you can see in the behind code) but the fields don't update, I assume this is because of the (rtn = true;) statement. Therefore I thought something like this might work:
rtn = (bool)reader["ADDRESS"];
However with this I get a specified cast is not valid, so I figure maybe the bool doesn't work in this context, I think it might work if I use string instead but how do I convert, I think rtn needs a value in regards to the reader right??
Basically I am just looking for a solution to which will update the text fields in the web form.
There are several problems with your code. The most obvious is that your code cannot ever return the data from the database. You are sending FIRSTNAME etc. to the web service - you are not returning them from the web service.
There is no reason to have a bool return from the service to tell you whether or not it succeeded. Let the service throw an exception if it failed. Instead, you should return the fields from the database as the return of the service.
In the service:
public class Person
{
public string FIRSTNAME {get;set;}
public string SURNAME {get;set;}
public string ADDRESS {get;set;}
}
[WebMethod]
public Person ReadPerson(int ID)
{
// ...
if (reader.Read())
{
// A record exists, thus return the value
Person p = new Person();
p.FIRSTNAME = (string)reader["FIRSTNAME"];
p.SURNAME = (string)reader["SURNAME"];
p.ADDRESS = (string)reader["ADDRESS"];
rtn = p;
}
connection.Close();
return rtn;
}
Also, you should not be using a WebMethod or an ASMX web service unless you have no choice. ASMX is a legacy technology which is kept around only for backwards compatability. It should not be used for new development. You should use WCF instead.
The other issues with your code are resolved below:
[WebMethod]
public Person ReadPerson(int id)
{
using (
var connection =
new SqlConnection(
#"Data Source=.\SQLEXPRESS;
AttachDbFilename='|DataDirectory|\Database.mdf';
Integrated Security=True;
User Instance=True")
)
{
connection.Open();
using (
var command =
new SqlCommand(#"
SELECT FIRSTNAME, SURNAME, ADDRESS
FROM PersonalDetails
WHERE ID = #id",
connection))
{
var idParameter =
command.Parameters.Add(
"#id", SqlDbType.Int);
idParameter.Value = id;
using (var reader = command.ExecuteReader())
{
if (!reader.Read())
{
return null;
}
return new Person
{
Firstname =
(string)
reader["FIRSTNAME"],
Surname =
(string)
reader["SURNAME"],
Address =
(string)
reader["ADDRESS"]
};
}
}
}
}
The main issue is that the SqlConnection, SqlCommand, and SqlDataReader all need to be instantiated inside of using blocks. This ensures that the objects are disposed of (closed) whether or not an exception is thrown.
Next, you should not get into the habit of building queries through string manipulation; not even using String.Format. That leaves you open to "SQL Injection" attacks. Using parameters resolves that problem. See "Commands and Parameters " in MSDN.
One last minor issue: I recommend that you get out of the habit of placing comments on obvious statements. For instance, it's not necessary to comment that Open opens the connection to the database, or that return returns a value.

Resources